library(Seurat)
library(dplyr)
library(patchwork)
library(sctransform)
library(ggplot2)
library(ggpubr)
library(tidyr)
library(ggrepel)
library(celldex) # Cell annotation.
library(SingleR) # Cell annotation.
library(parallel) # detectCores()
library(future) # Allows parallelization in Seurat.
library(readODS) # Allows ods file import to add sample info
# Set up Seurat pararell computing.
options(parallelly.fork.enable = TRUE)
plan("multicore", workers = detectCores())

1. Intro: There is actually batch effect.

We recently found out that some clusters are exclusively formed by cells of a single run, indicanting the presence of batch effect.


p1 <- DimPlot(SCP_data, reduction = "umap", label = TRUE, repel = TRUE, label.size = 4) + theme(axis.title = element_text(size = 15), legend.text = element_text(size = 10), axis.text = element_text(size = 10)) + guides(colour = guide_legend(override.aes = list(size = 3)))

p2 <- DimPlot(SCP_data, reduction = "umap", label = TRUE, repel = TRUE, label.size = 4, group.by = "Sample_Name") + theme(axis.title = element_text(size = 15), legend.text = element_text(size = 10), axis.text = element_text(size = 10)) + guides(colour = guide_legend(override.aes = list(size = 3)))

p3 <- DimPlot(SCP_data, reduction = "umap", label = FALSE, repel = TRUE, label.size = 4, group.by = "orig.ident") + theme(axis.title = element_text(size = 15), legend.text = element_text(size = 10), axis.text = element_text(size = 10)) + guides(colour = guide_legend(override.aes = list(size = 3)))

p1 + p2 + p3

Note: Cluster 4 is 100% run4 and cluster 15 is 100% run 3. They output an error and we don’t want to expend much time on this.

As we can see in the image, cluster 4 and cluster 15 is composed exclusively of cells from run4 and run3, respectively. Also, analyzing the proportions of each run throws an unequal distribution of cells from each batch.


clusters <- levels(SCP_data$seurat_clusters)
df <- data.frame()
for(i in 1:length(clusters)){
  if (clusters[i] != 4 & clusters[i] != 14)  {
        cur_df <- as.data.frame(SCP_data@meta.data %>% subset(seurat_clusters == clusters[i]) %>% .$orig.ident %>% table() /
    table(SCP_data$orig.ident))
  
    cur_df$Freq <- cur_df$Freq * 1/(sum(cur_df$Freq))
  
    cur_df$cluster <- clusters[i]
    df <- rbind(df, cur_df)
  } else {
    cur_df <- as.data.frame(SCP_data@meta.data %>% subset(seurat_clusters == clusters[i]) %>% .$orig.ident %>% table())
  
    cur_df$Freq <- cur_df$Freq * 1/(sum(cur_df$Freq))
  
    cur_df$cluster <- clusters[i]
    df <- rbind(df, cur_df)
  }
}


RunFreq.noInt <- ggplot(df, aes(y=Freq, x=cluster, fill=.)) +
  geom_bar(stat='identity') +
  scale_y_continuous(expand = c(0,0)) +
  ylab('normalized proportion') +
  theme(
    panel.grid.major=element_blank(),
    panel.grid.minor=element_blank(),
    axis.text.x = element_text(angle=45, hjust=1),
    axis.title.x = element_blank(),
    legend.title = element_blank(),
    axis.line.y = element_blank(),
    axis.line.x = element_blank()
  )
RunFreq.noInt

We also re-visualize the PCA plot:


Idents(SCP_data) <- "orig.ident"
DimPlot(SCP_data, reduction = "pca")

2. Introduction to data integration with Seurat.

Seurat offers methods to integrate data from different batches (different sequencing runs, different samples, etc.). In v5, a new method called IntegrateLayers they easily perform the whole pipeline in a few steps. The first of them is to split the data according to the source of batch effect (in our case by run).


# The split method splits the given slot according to the indicated information.
SCP_data[["RNA"]] <- split(SCP_data[["RNA"]], f = SCP_data$orig.ident)

2.1. Normalize and apply data integration.

It is necessary to normalize the data before integration. According to maintainers (https://github.com/satijalab/seurat/issues/4811) it doesn’t mind to normalize before or after splitting.

Since recent discussion indicates that according to the use case sometimes is better to work on raw, non-integrated values (https://github.com/satijalab/seurat/discussions/5452?utm_source=pocket_saves), we also perform the standard normalization workflow.


# Standard normalization.
SCP_data <- NormalizeData(SCP_data)
SCP_data <- FindVariableFeatures(SCP_data, nfeatures = 3000)
Calculating gene variances
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating feature variances of standardized and clipped values
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating gene variances
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating feature variances of standardized and clipped values
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating gene variances
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating feature variances of standardized and clipped values
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating gene variances
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating feature variances of standardized and clipped values
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
SCP_data <- ScaleData(SCP_data)

We now run SCTransform, PCA and the integration.


# Launch sct transform and run PCA.
SCP_data <- SCTransform(SCP_data, vst.flavor = "v2", vars.to.regress = "percent.mt")
SCP_data <- RunPCA(SCP_data, assay = "SCT")

# Integration.
SCP_data <- IntegrateLayers(
  object = SCP_data, method = HarmonyIntegration,
  normalization.method = "SCT",
  verbose = FALSE
)

There are several methods for integration, but according to some sources (https://genomebiology.biomedcentral.com/articles/10.1186/s13059-019-1850-9), the best ones are Harmony, Seurat’s CCA and scVII (requires setting up a conda environment and installing reticulate, see documentation). We choose Harmony for being well-integrated with Seruat, and performing pretty well with low computational effort.

If we re-visualize the PCA plot, we appreciate a bigger overlap between runs.


Idents(SCP_data) <- "orig.ident"
DimPlot(SCP_data, reduction = "pca")

2.2. Set dimensionality.

While the elbow appears around the 15th PC, we extend the included PCs up to the 30th following the new guidelines by the Seurat developers after SCTransform normalization implementation.


ElbowPlot(SCP_data, ndims = 50, reduction = "pca") # choose 30

The heatmap and the feature plot give us information about the significance and composition of each PC.


DimHeatmap(SCP_data, dims = 1:30, balanced = TRUE, reduction = "pca")


VizDimLoadings(SCP_data, dims = 1:30, reduction = "pca")

3. Find variable top variable features.

WARING: Since the data is splitted into 4 layers, is not possible to plot the top variable genes, but we still can run FindVariableFeatures and access the list using VariableFeatrues.


# SCP_data <- FindVariableFeatures(SCP_data, selection.method = "vst", nfeatures = 3000, assay = "SCT")

# Genes with differential expression in different cells are good candidates to be biomarkers.
# Identify the 20 most highly variable genes
top <- head(VariableFeatures(SCP_data, assay = "SCT",layer = run), 20)

4. Clustering.

Clustering resolution fine-tuning is performed by a separated .Rmd file (Resolution fine-tuning.Rmd), giving 0.8 as a appropriate value for clustering.

It is important to notice that a new reduction is created called “harmony”. We need to indicate this as the reduction to use in the clustering.


# Resolution fine-tuned in a separate Rmd.
SCP_data <- FindNeighbors(SCP_data, dims = 1:30, reduction = "harmony")
SCP_data <- FindClusters(SCP_data, resolution = 0.8, ) # Default resolution = 0.8
Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck

Number of nodes: 13365
Number of edges: 492091

Running Louvain algorithm...
Maximum modularity in 10 random starts: 0.9139
Number of communities: 24
Elapsed time: 1 seconds
SCP_data <- RunUMAP(SCP_data, dims = 1:30, reduction = "harmony")
Using method 'umap'
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|

We now appreciate a more homogeneous distribution of the cells from each run among the clusters:


p1 <- DimPlot(SCP_data, reduction = "umap", label = TRUE, repel = TRUE, label.size = 4) + theme(axis.title = element_text(size = 15), legend.text = element_text(size = 10), axis.text = element_text(size = 10)) + guides(colour = guide_legend(override.aes = list(size = 3)))

p2 <- DimPlot(SCP_data, reduction = "umap", label = TRUE, repel = TRUE, label.size = 4, group.by = "Sample_Name") + theme(axis.title = element_text(size = 15), legend.text = element_text(size = 10), axis.text = element_text(size = 10)) + guides(colour = guide_legend(override.aes = list(size = 3)))

p3 <- DimPlot(SCP_data, reduction = "umap", label = FALSE, repel = TRUE, label.size = 4, group.by = "orig.ident") + theme(axis.title = element_text(size = 15), legend.text = element_text(size = 10), axis.text = element_text(size = 10)) + guides(colour = guide_legend(override.aes = list(size = 3)))

p1 + p2 + p3

clusters <- levels(SCP_data$seurat_clusters)
df <- data.frame()
for(i in 1:length(clusters)){
      cur_df <- as.data.frame(SCP_data@meta.data %>% subset(seurat_clusters == clusters[i]) %>% .$orig.ident %>% table() /
  table(SCP_data$orig.ident))

  cur_df$Freq <- cur_df$Freq * 1/(sum(cur_df$Freq))

  cur_df$cluster <- clusters[i]
  df <- rbind(df, cur_df)
}

RunFreq.Int <- ggplot(df, aes(y=Freq, x=cluster, fill=.)) +
  geom_bar(stat='identity') +
  scale_y_continuous(expand = c(0,0)) +
  ylab('normalized proportion') +
  theme(
    panel.grid.major=element_blank(),
    panel.grid.minor=element_blank(),
    axis.text.x = element_text(angle=45, hjust=1),
    axis.title.x = element_blank(),
    legend.title = element_blank(),
    axis.line.y = element_blank(),
    axis.line.x = element_blank()
  )
RunFreq.Int

Proportions are a bit more equilibrated now.


RunFreq.noInt + RunFreq.Int

4.1. Cluster QC.

Cluster QC shows homogeneous characteristics across the clusters with the exception of cluster 22 (abnormal low number of features). Despite what it might look like, this actually conforms and advantage, as if that specific group of cells give inconsistent results, because they have been isolated in their own cluster we can move forward just ignoring or removing it.


# Visualize QC metrics as a violin plot
VlnPlot(SCP_data, features = c("nFeature_RNA", "nCount_RNA", "percent.mt"), ncol = 3) + NoLegend()


# Zoom in on nFeature_RNA violin plot.
VlnPlot(SCP_data, features = "nFeature_RNA", ncol = 1) + ylim(0, 2500) + NoLegend()


# Visualize relationships in metadata to detect outliers with FeatureScatter function
plot1 <- FeatureScatter(SCP_data, feature1 = "nCount_RNA", feature2 = "percent.mt")
plot2 <- FeatureScatter(SCP_data, feature1 = "nCount_RNA", feature2 = "nFeature_RNA")
plot1 + NoLegend() + plot2 + NoLegend()

5. Annotation.

5.1. By-cell annotation.

Cell-by-cell annotation identifies 30 different cell types based on the HumanPrimaryCellAtlas, which distribution pretty much coincides with the cluster layout.

For this step, we now need to join the layers before exporting to a SCExperiment object.


# Using celldex and SingleR packages.
# Download reference data from celldex.
reference <- HumanPrimaryCellAtlasData()

# Join layers before conversion. SingleR uses the RNA assay.
merged.SCexp <- JoinLayers(SCP_data, assay = "RNA") 

# Convert Seurat object into a SingleCellExperiment Object for SingleR input.
merged.SCexp <- as.SingleCellExperiment(merged.SCexp)

SingleR.annotation <- SingleR(test = merged.SCexp, ref = reference, assay.type.test = "logcounts", labels = reference$label.main, num.threads = detectCores())

SCP_data[["cell.labels"]] <- SingleR.annotation$labels

DimPlot(SCP_data, reduction = "umap", group.by = "cell.labels", label = TRUE, repel = TRUE, label.size = 4) + theme(axis.title = element_text(size = 15), legend.text = element_text(size = 10), axis.text = element_text(size = 10)) + guides(colour = guide_legend(override.aes = list(size = 3)))

5.2. By-cluster annotation.

We create our own composite cluster names by adding the cluster annotation to the cluster number provided by Suerat. Thus, what we see is an estimation of the cell type that better fits the genetic landscape of each cluster.


# Obtaining a vector containing the cluster of each cell in order.

# Get the factor contained in the SeuratObject with all this information.
clusters <- SCP_data@meta.data[["seurat_clusters"]]

# The cluster information for each cell is contain as a factor which levels coincide with the total number of clusters found by FindClusters(). An approach to transform this factor into a character vector is the following:
# Obtain the list of clusters with levels(clusters). This outputs a character vector containing the levles of the factor. After that, we use the factor itself as an index to access the levels vector. When using a factor as an index, R does not use the labels itself (which in this case are string, so if used as indexes would cause an error), but the internal numeric index the factor contains. That way, for each cluster label associated with a cell in the factor, we access its numeric index and map it to the levels vectors (which coincides), thus obtaining each cell label as an unique character value. Each cell label is then storage as a character (the as.character is added as a control method since SingleR only admits strings as labels) in a vector. The vector contains the cluster label for each cell as a character value in the same order as each cell appears in the dataset, so the by-cluster annotation doesn't assign the cells to an incorrect cluster.
clusters <- as.character(levels(clusters)[clusters])

# reference <- HumanPrimaryCellAtlasData()

# merged.SCexp <- as.SingleCellExperiment(SCP_data)

# We input the cluster vector using the clusters parameter.
SingleR.annotation <- SingleR(test = merged.SCexp, ref = reference, assay.type.test = "logcounts", labels = reference$label.main, clusters = clusters, num.threads = detectCores())

SCP_data[["cluster.labels"]] <- SingleR.annotation$labels

# We composite the cluster name. That way when 2 clusters' names are the same Seurat doesn't merge the labels.

# Get clusters levels accessing the SeuratObject variable as a df and then accessing the df as a column.
cluster_number <- levels(SCP_data[["seurat_clusters"]][1, ])

# Get annotation labels.
cluster_annotation <- SingleR.annotation$labels

# Since cluster levels and labels are in the same order, we composite the new names using paste0 (sort of equivalent to fstrings in python).
new.clusters.ids <- paste0(cluster_number, "-", cluster_annotation)

# Add names to each value of the clusters id vector so Seurat can take it as a valid input for RenameIdents.
names(new.clusters.ids) <- levels(SCP_data)
SCP_data <- RenameIdents(SCP_data, new.clusters.ids)
SCP_data[["cell.cluster.labels"]] <- Idents(SCP_data)

DimPlot(SCP_data, reduction = "umap", label = TRUE, repel = TRUE, label.size = 4) + theme(axis.title = element_text(size = 15), legend.text = element_text(size = 10), axis.text = element_text(size = 10)) + guides(colour = guide_legend(override.aes = list(size = 3)))

6. Exploratory analysis.

Here, we start the more deep and accurate analysis of the dataset.

We repeat this analysis to follow the new guidelines provided here: https://satijalab.org/seurat/articles/parsebio_sketch_integration

As recommended by Soneson et all. and Crowell et al., we use an aggregation-based (pseudobulk) workflow using the raw counts. We aggregate all cells within the same cell type and sample using the AggregateExpression function. This returns a Seurat object where each ‘cell’ represents the pseudobulk profile of one cell type in one individual.

6.1. Finding cluster enriched in T samples.

First, we would take a look at the proportion of cells from the different groups (T, N, NAT and AT) on each cluster.

For that we will plot the frequency of each sample oAs recommended by Soneson et all. and Crowell et al., we use an aggregation-based (pseudobulk) workfln each cluster (that is, the fraction of the total cells of that given type present on each cluster).


# Sumarize() performs an operation over a row of a dataframe, for example mean() or count n().

# Slots are dataframes, so it can be used by dplyr.
prop_cell_by_sample <- SCP_data@meta.data %>% group_by(Sample_Name, cell.cluster.labels) %>% 
  summarise(n = n()) %>% # For each cluster, group the cells from the same sample together and count them.
  ungroup() %>% group_by(Sample_Name) %>%
  mutate(freq = n / sum(n)) %>% # Group them now by sample, add up the total number of cells from that sample (regardless of the cluster they belong to). Then, divide each n value (number of cells of a sample in a certain cluster), obtaining which fraction of the total cells of that given type is present on each cluster.
  left_join(SCP_data@meta.data %>% select(Sample_Name, Sample_Group) %>% unique()) # Add metadata info available for the data, select only the Sample_Name and Sample_Group fields and delete duplicates.

For now, will be only focus on comparing the confirmed tumoral (T) and healthy (N) samples.


# Filter only the desired groups "N" and "T"
prop_cell_by_sample_filtered <- prop_cell_by_sample %>%
  filter(Sample_Group %in% c("N", "T"))

We apply the Wilcoxon test to find out significant differences between sample groups. We found out that the cluster 18 (annotated as endothelial cells) is the only group with a significant enrichment in tumoral cells.


# Extract data for Sample_Group "T" and other groups

group_T <- prop_cell_by_sample[prop_cell_by_sample$Sample_Group == "T", ]
group_N <- prop_cell_by_sample[prop_cell_by_sample$Sample_Group == "N", ]

# Perform t-test for each cluster
clusters <- levels(prop_cell_by_sample$cell.cluster.labels)
p_values <- numeric(length(clusters))

for (i in seq_along(clusters)) {
  
  cluster_data_T <- group_T[group_T$cell.cluster.labels == clusters[i], "freq"] 
  
  cluster_data_N <- group_N[group_N$cell.cluster.labels == clusters[i], "freq"]

  # Perform test 
  test_result <- wilcox.test(cluster_data_T$freq, cluster_data_N$freq)

  # Store p-value 
  p_values[i] <- test_result$p.value 
  
  }

# Identify clusters with significant enrichment (e.g., p-value < 0.05)

enriched_clusters <- clusters[p_values < 0.05]

# Print or visualize the enriched clusters

print(enriched_clusters) 
character(0)
print(p_values)
 [1] 1.00000000 0.49225774 0.95779221 0.36763237 0.79245754 0.09340659 0.41358641 0.79245754 0.23976024 0.63536464 0.71278721
[12] 0.95779221 0.18056943 0.32767233 0.27212787 0.95779221 0.94971695 0.11348651 0.21978022 0.60639361 0.81818182 0.55555556
[23] 1.00000000 0.16666667

Unfortunaletly, after applying integration, no cluster is significant. We plot the results along the statistics in a paper-ready figure.


# Plot only the desired groups
enriched_clusters <- ggboxplot(prop_cell_by_sample_filtered, x = "Sample_Group", y = "freq",
          color = "Sample_Group",  palette = "jco",
          add = "jitter") +
facet_wrap(~cell.cluster.labels, scales = "free", nrow = 6) +
theme(legend.position = "none") +
xlab("Sample Group") + ylab("Frequency") +
stat_compare_means(aes(label = ..p.signif..), label.x = 1.5)

enriched_clusters

6.1.1. Finding differentially expressed genes in tumoral-enriched clusters.

Anyway, in order to test this new method, we will now perform a DE analysis on cluster 18 by comparing cells coming from T samples (tumoral) vs healthy samples (N).


# By-cell method (uses integrated and SCTransformed data)
SCP_data <- PrepSCTFindMarkers(SCP_data)
cluster18.markers.cell <- FindMarkers(SCP_data, ident.1 = "T", ident.2 = "N", group.by = "Sample_Group", subset.ident = "18-T_cells", assay = "SCT", recorrect_umi = FALSE)

# Using pseudobulk.
bulk <- AggregateExpression(SCP_data, return.seurat = T, slot = "counts", assays = "RNA", group.by = c("seurat_clusters",
    "Sample_Name", "Sample_Group"))

  |                                                                                                                         
  |                                                                                                                   |   0%
  |                                                                                                                         
  |=                                                                                                                  |   1%
  |                                                                                                                         
  |==                                                                                                                 |   1%
  |                                                                                                                         
  |==                                                                                                                 |   2%
  |                                                                                                                         
  |===                                                                                                                |   2%
  |                                                                                                                         
  |===                                                                                                                |   3%
  |                                                                                                                         
  |====                                                                                                               |   3%
  |                                                                                                                         
  |====                                                                                                               |   4%
  |                                                                                                                         
  |=====                                                                                                              |   4%
  |                                                                                                                         
  |=====                                                                                                              |   5%
  |                                                                                                                         
  |======                                                                                                             |   5%
  |                                                                                                                         
  |======                                                                                                             |   6%
  |                                                                                                                         
  |=======                                                                                                            |   6%
  |                                                                                                                         
  |========                                                                                                           |   7%
  |                                                                                                                         
  |=========                                                                                                          |   7%
  |                                                                                                                         
  |=========                                                                                                          |   8%
  |                                                                                                                         
  |==========                                                                                                         |   8%
  |                                                                                                                         
  |==========                                                                                                         |   9%
  |                                                                                                                         
  |===========                                                                                                        |   9%
  |                                                                                                                         
  |===========                                                                                                        |  10%
  |                                                                                                                         
  |============                                                                                                       |  10%
  |                                                                                                                         
  |============                                                                                                       |  11%
  |                                                                                                                         
  |=============                                                                                                      |  11%
  |                                                                                                                         
  |=============                                                                                                      |  12%
  |                                                                                                                         
  |==============                                                                                                     |  12%
  |                                                                                                                         
  |==============                                                                                                     |  13%
  |                                                                                                                         
  |===============                                                                                                    |  13%
  |                                                                                                                         
  |================                                                                                                   |  14%
  |                                                                                                                         
  |=================                                                                                                  |  14%
  |                                                                                                                         
  |=================                                                                                                  |  15%
  |                                                                                                                         
  |==================                                                                                                 |  15%
  |                                                                                                                         
  |==================                                                                                                 |  16%
  |                                                                                                                         
  |===================                                                                                                |  16%
  |                                                                                                                         
  |===================                                                                                                |  17%
  |                                                                                                                         
  |====================                                                                                               |  17%
  |                                                                                                                         
  |====================                                                                                               |  18%
  |                                                                                                                         
  |=====================                                                                                              |  18%
  |                                                                                                                         
  |=====================                                                                                              |  19%
  |                                                                                                                         
  |======================                                                                                             |  19%
  |                                                                                                                         
  |=======================                                                                                            |  20%
  |                                                                                                                         
  |========================                                                                                           |  21%
  |                                                                                                                         
  |=========================                                                                                          |  21%
  |                                                                                                                         
  |=========================                                                                                          |  22%
  |                                                                                                                         
  |==========================                                                                                         |  22%
  |                                                                                                                         
  |==========================                                                                                         |  23%
  |                                                                                                                         
  |===========================                                                                                        |  23%
  |                                                                                                                         
  |===========================                                                                                        |  24%
  |                                                                                                                         
  |============================                                                                                       |  24%
  |                                                                                                                         
  |============================                                                                                       |  25%
  |                                                                                                                         
  |=============================                                                                                      |  25%
  |                                                                                                                         
  |=============================                                                                                      |  26%
  |                                                                                                                         
  |==============================                                                                                     |  26%
  |                                                                                                                         
  |===============================                                                                                    |  27%
  |                                                                                                                         
  |================================                                                                                   |  27%
  |                                                                                                                         
  |================================                                                                                   |  28%
  |                                                                                                                         
  |=================================                                                                                  |  28%
  |                                                                                                                         
  |=================================                                                                                  |  29%
  |                                                                                                                         
  |==================================                                                                                 |  29%
  |                                                                                                                         
  |==================================                                                                                 |  30%
  |                                                                                                                         
  |===================================                                                                                |  30%
  |                                                                                                                         
  |===================================                                                                                |  31%
  |                                                                                                                         
  |====================================                                                                               |  31%
  |                                                                                                                         
  |====================================                                                                               |  32%
  |                                                                                                                         
  |=====================================                                                                              |  32%
  |                                                                                                                         
  |=====================================                                                                              |  33%
  |                                                                                                                         
  |======================================                                                                             |  33%
  |                                                                                                                         
  |=======================================                                                                            |  34%
  |                                                                                                                         
  |========================================                                                                           |  34%
  |                                                                                                                         
  |========================================                                                                           |  35%
  |                                                                                                                         
  |=========================================                                                                          |  35%
  |                                                                                                                         
  |=========================================                                                                          |  36%
  |                                                                                                                         
  |==========================================                                                                         |  36%
  |                                                                                                                         
  |==========================================                                                                         |  37%
  |                                                                                                                         
  |===========================================                                                                        |  37%
  |                                                                                                                         
  |===========================================                                                                        |  38%
  |                                                                                                                         
  |============================================                                                                       |  38%
  |                                                                                                                         
  |============================================                                                                       |  39%
  |                                                                                                                         
  |=============================================                                                                      |  39%
  |                                                                                                                         
  |==============================================                                                                     |  40%
  |                                                                                                                         
  |===============================================                                                                    |  41%
  |                                                                                                                         
  |================================================                                                                   |  41%
  |                                                                                                                         
  |================================================                                                                   |  42%
  |                                                                                                                         
  |=================================================                                                                  |  42%
  |                                                                                                                         
  |=================================================                                                                  |  43%
  |                                                                                                                         
  |==================================================                                                                 |  43%
  |                                                                                                                         
  |==================================================                                                                 |  44%
  |                                                                                                                         
  |===================================================                                                                |  44%
  |                                                                                                                         
  |===================================================                                                                |  45%
  |                                                                                                                         
  |====================================================                                                               |  45%
  |                                                                                                                         
  |====================================================                                                               |  46%
  |                                                                                                                         
  |=====================================================                                                              |  46%
  |                                                                                                                         
  |======================================================                                                             |  47%
  |                                                                                                                         
  |=======================================================                                                            |  47%
  |                                                                                                                         
  |=======================================================                                                            |  48%
  |                                                                                                                         
  |========================================================                                                           |  48%
  |                                                                                                                         
  |========================================================                                                           |  49%
  |                                                                                                                         
  |=========================================================                                                          |  49%
  |                                                                                                                         
  |=========================================================                                                          |  50%
  |                                                                                                                         
  |==========================================================                                                         |  50%
  |                                                                                                                         
  |==========================================================                                                         |  51%
  |                                                                                                                         
  |===========================================================                                                        |  51%
  |                                                                                                                         
  |===========================================================                                                        |  52%
  |                                                                                                                         
  |============================================================                                                       |  52%
  |                                                                                                                         
  |============================================================                                                       |  53%
  |                                                                                                                         
  |=============================================================                                                      |  53%
  |                                                                                                                         
  |==============================================================                                                     |  54%
  |                                                                                                                         
  |===============================================================                                                    |  54%
  |                                                                                                                         
  |===============================================================                                                    |  55%
  |                                                                                                                         
  |================================================================                                                   |  55%
  |                                                                                                                         
  |================================================================                                                   |  56%
  |                                                                                                                         
  |=================================================================                                                  |  56%
  |                                                                                                                         
  |=================================================================                                                  |  57%
  |                                                                                                                         
  |==================================================================                                                 |  57%
  |                                                                                                                         
  |==================================================================                                                 |  58%
  |                                                                                                                         
  |===================================================================                                                |  58%
  |                                                                                                                         
  |===================================================================                                                |  59%
  |                                                                                                                         
  |====================================================================                                               |  59%
  |                                                                                                                         
  |=====================================================================                                              |  60%
  |                                                                                                                         
  |======================================================================                                             |  61%
  |                                                                                                                         
  |=======================================================================                                            |  61%
  |                                                                                                                         
  |=======================================================================                                            |  62%
  |                                                                                                                         
  |========================================================================                                           |  62%
  |                                                                                                                         
  |========================================================================                                           |  63%
  |                                                                                                                         
  |=========================================================================                                          |  63%
  |                                                                                                                         
  |=========================================================================                                          |  64%
  |                                                                                                                         
  |==========================================================================                                         |  64%
  |                                                                                                                         
  |==========================================================================                                         |  65%
  |                                                                                                                         
  |===========================================================================                                        |  65%
  |                                                                                                                         
  |===========================================================================                                        |  66%
  |                                                                                                                         
  |============================================================================                                       |  66%
  |                                                                                                                         
  |=============================================================================                                      |  67%
  |                                                                                                                         
  |==============================================================================                                     |  67%
  |                                                                                                                         
  |==============================================================================                                     |  68%
  |                                                                                                                         
  |===============================================================================                                    |  68%
  |                                                                                                                         
  |===============================================================================                                    |  69%
  |                                                                                                                         
  |================================================================================                                   |  69%
  |                                                                                                                         
  |================================================================================                                   |  70%
  |                                                                                                                         
  |=================================================================================                                  |  70%
  |                                                                                                                         
  |=================================================================================                                  |  71%
  |                                                                                                                         
  |==================================================================================                                 |  71%
  |                                                                                                                         
  |==================================================================================                                 |  72%
  |                                                                                                                         
  |===================================================================================                                |  72%
  |                                                                                                                         
  |===================================================================================                                |  73%
  |                                                                                                                         
  |====================================================================================                               |  73%
  |                                                                                                                         
  |=====================================================================================                              |  74%
  |                                                                                                                         
  |======================================================================================                             |  74%
  |                                                                                                                         
  |======================================================================================                             |  75%
  |                                                                                                                         
  |=======================================================================================                            |  75%
  |                                                                                                                         
  |=======================================================================================                            |  76%
  |                                                                                                                         
  |========================================================================================                           |  76%
  |                                                                                                                         
  |========================================================================================                           |  77%
  |                                                                                                                         
  |=========================================================================================                          |  77%
  |                                                                                                                         
  |=========================================================================================                          |  78%
  |                                                                                                                         
  |==========================================================================================                         |  78%
  |                                                                                                                         
  |==========================================================================================                         |  79%
  |                                                                                                                         
  |===========================================================================================                        |  79%
  |                                                                                                                         
  |============================================================================================                       |  80%
  |                                                                                                                         
  |=============================================================================================                      |  81%
  |                                                                                                                         
  |==============================================================================================                     |  81%
  |                                                                                                                         
  |==============================================================================================                     |  82%
  |                                                                                                                         
  |===============================================================================================                    |  82%
  |                                                                                                                         
  |===============================================================================================                    |  83%
  |                                                                                                                         
  |================================================================================================                   |  83%
  |                                                                                                                         
  |================================================================================================                   |  84%
  |                                                                                                                         
  |=================================================================================================                  |  84%
  |                                                                                                                         
  |=================================================================================================                  |  85%
  |                                                                                                                         
  |==================================================================================================                 |  85%
  |                                                                                                                         
  |==================================================================================================                 |  86%
  |                                                                                                                         
  |===================================================================================================                |  86%
  |                                                                                                                         
  |====================================================================================================               |  87%
  |                                                                                                                         
  |=====================================================================================================              |  87%
  |                                                                                                                         
  |=====================================================================================================              |  88%
  |                                                                                                                         
  |======================================================================================================             |  88%
  |                                                                                                                         
  |======================================================================================================             |  89%
  |                                                                                                                         
  |=======================================================================================================            |  89%
  |                                                                                                                         
  |=======================================================================================================            |  90%
  |                                                                                                                         
  |========================================================================================================           |  90%
  |                                                                                                                         
  |========================================================================================================           |  91%
  |                                                                                                                         
  |=========================================================================================================          |  91%
  |                                                                                                                         
  |=========================================================================================================          |  92%
  |                                                                                                                         
  |==========================================================================================================         |  92%
  |                                                                                                                         
  |==========================================================================================================         |  93%
  |                                                                                                                         
  |===========================================================================================================        |  93%
  |                                                                                                                         
  |============================================================================================================       |  94%
  |                                                                                                                         
  |=============================================================================================================      |  94%
  |                                                                                                                         
  |=============================================================================================================      |  95%
  |                                                                                                                         
  |==============================================================================================================     |  95%
  |                                                                                                                         
  |==============================================================================================================     |  96%
  |                                                                                                                         
  |===============================================================================================================    |  96%
  |                                                                                                                         
  |===============================================================================================================    |  97%
  |                                                                                                                         
  |================================================================================================================   |  97%
  |                                                                                                                         
  |================================================================================================================   |  98%
  |                                                                                                                         
  |=================================================================================================================  |  98%
  |                                                                                                                         
  |=================================================================================================================  |  99%
  |                                                                                                                         
  |================================================================================================================== |  99%
  |                                                                                                                         
  |===================================================================================================================| 100%
# We don't know why it adds a "g" after pseudobulking. 
cluster18 <- subset(bulk, seurat_clusters == "g18")
# As we are using bulks instead of cells, we need to change the test to a more appropiate one.
cluster18.markers.bulk <- FindMarkers(cluster18, ident.1 = "T", ident.2 = "N", group.by = "Sample_Group", test.use = "DESeq2")

Plot cell-based DE:


FC = log2(1.5) # Set FC threshold.

# Add a column to the data frame to specify if they are UP- or DOWN- regulated (log2fc respectively positive or negative).
cluster18.markers.cell$diffexpressed <- "NO"
# if FC > 1.5 (log2FC > ~0.6) and pvalue < 0.05, set as "UP".
cluster18.markers.cell$diffexpressed[cluster18.markers.cell$avg_log2FC > FC & cluster18.markers.cell$p_val < 0.05] <- "UP"
# if FC < 0.666 (invers 1/1.5 calculated as log2FC < ~-0.6) and pvalue < 0.05, set as "DOWN".
cluster18.markers.cell$diffexpressed[cluster18.markers.cell$avg_log2FC < -FC & cluster18.markers.cell$p_val < 0.05] <- "DOWN"

cluster18.markers.cell <- cluster18.markers.cell %>%
  arrange(p_val) %>%
  mutate(gene_symbol = rownames(.)) %>%
  group_by(diffexpressed) %>%
  mutate(delabel = if_else(diffexpressed %in% c("UP", "DOWN") & row_number() <= 10, gene_symbol, NA)) %>%
  ungroup()

cell.DE <- ggplot(cluster18.markers.cell, aes(x = avg_log2FC, y = -log10(p_val), col = diffexpressed, label = delabel)) +
  geom_vline(xintercept = c(-FC, FC), col = "grey", linetype = 'dashed') +
  geom_hline(yintercept = -log10(0.05), col = "grey", linetype = 'dashed') +
  geom_point(size = 2) +
  scale_color_manual(values = c("#00AFBB", "grey", "#bb0c00"), # to set the colours of our variable
                     labels = c("Downregulated", "Not significant", "Upregulated")) + # to set the labels in case we want to overwrite the categories from the dataframe (UP, DOWN, NO)
  labs(color = NULL, #legend_title,
       x = expression("log"[2]*"FC"), y = expression("-log"[10]*"p-value")) +
  theme_classic() +
  scale_x_continuous(breaks = seq(-10, 10, 2)) + # to customise the breaks in the x axis
  geom_text_repel(box.padding = 0.6, max.overlaps = Inf) # To show all labels

Plot bulk-based DE:


# Add a column to the data frame to specify if they are UP- or DOWN- regulated (log2fc respectively positive or negative).
cluster18.markers.bulk$diffexpressed <- "NO"
# if FC > 1.5 (log2FC > ~0.6) and pvalue < 0.05, set as "UP".
cluster18.markers.bulk$diffexpressed[cluster18.markers.bulk$avg_log2FC > FC & cluster18.markers.bulk$p_val < 0.05] <- "UP"
# if FC < 0.666 (invers 1/1.5 calculated as log2FC < ~-0.6) and pvalue < 0.05, set as "DOWN".
cluster18.markers.bulk$diffexpressed[cluster18.markers.bulk$avg_log2FC < -FC & cluster18.markers.bulk$p_val < 0.05] <- "DOWN"

cluster18.markers.bulk <- cluster18.markers.bulk %>%
  arrange(p_val_adj) %>%
  mutate(gene_symbol = rownames(.)) %>%
  group_by(diffexpressed) %>%
  mutate(delabel = if_else(diffexpressed %in% c("UP", "DOWN") & row_number() <= 10, gene_symbol, NA)) %>%
  ungroup()

bulk.DE <- ggplot(cluster18.markers.bulk, aes(x = avg_log2FC, y = -log10(p_val), col = diffexpressed, label = delabel)) +
  geom_vline(xintercept = c(-FC, FC), col = "grey", linetype = 'dashed') +
  geom_hline(yintercept = -log10(0.05), col = "grey", linetype = 'dashed') +
  geom_point(size = 2) +
  scale_color_manual(values = c("#00AFBB", "grey", "#bb0c00"), # to set the colours of our variable
                     labels = c("Downregulated", "Not significant", "Upregulated")) + # to set the labels in case we want to overwrite the categories from the dataframe (UP, DOWN, NO)
  labs(color = NULL, #legend_title,
       x = expression("log"[2]*"FC"), y = expression("-log"[10]*"p-value")) +
  theme_classic() +
  scale_x_continuous(breaks = seq(-10, 10, 2)) + # to customise the breaks in the x axis
  geom_text_repel(box.padding = 0.6, max.overlaps = Inf) # To show all labels

Compare:


cell.DE + bulk.DE


sessionInfo()
R version 4.3.3 (2024-02-29)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 22.04.4 LTS

Matrix products: default
BLAS:   /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.10.0 
LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.10.0

locale:
 [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C               LC_TIME=es_ES.UTF-8        LC_COLLATE=en_US.UTF-8    
 [5] LC_MONETARY=es_ES.UTF-8    LC_MESSAGES=en_US.UTF-8    LC_PAPER=es_ES.UTF-8       LC_NAME=C                 
 [9] LC_ADDRESS=C               LC_TELEPHONE=C             LC_MEASUREMENT=es_ES.UTF-8 LC_IDENTIFICATION=C       

time zone: Europe/Madrid
tzcode source: system (glibc)

attached base packages:
[1] parallel  stats4    stats     graphics  grDevices datasets  utils     methods   base     

other attached packages:
 [1] readODS_2.2.0               future_1.33.2               SingleR_2.4.1               celldex_1.12.0             
 [5] SummarizedExperiment_1.32.0 Biobase_2.62.0              GenomicRanges_1.54.1        GenomeInfoDb_1.38.8        
 [9] IRanges_2.36.0              S4Vectors_0.40.2            BiocGenerics_0.48.1         MatrixGenerics_1.14.0      
[13] matrixStats_1.3.0           ggrepel_0.9.5               tidyr_1.3.1                 ggpubr_0.6.0               
[17] ggplot2_3.5.1               sctransform_0.4.1           patchwork_1.2.0             dplyr_1.1.4                
[21] Seurat_5.0.3                SeuratObject_5.0.1          sp_2.1-3                   

loaded via a namespace (and not attached):
  [1] RcppAnnoy_0.0.22              splines_4.3.3                 later_1.3.2                   filelock_1.0.3               
  [5] bitops_1.0-7                  tibble_3.2.1                  polyclip_1.10-6               fastDummies_1.7.3            
  [9] lifecycle_1.0.4               rstatix_0.7.2                 globals_0.16.3                lattice_0.22-6               
 [13] MASS_7.3-60.0.1               backports_1.4.1               magrittr_2.0.3                limma_3.58.1                 
 [17] plotly_4.10.4                 yaml_2.3.8                    httpuv_1.6.15                 glmGamPoi_1.14.3             
 [21] spam_2.10-0                   spatstat.sparse_3.0-3         reticulate_1.36.1             cowplot_1.1.3                
 [25] pbapply_1.7-2                 DBI_1.2.2                     RColorBrewer_1.1-3            abind_1.4-5                  
 [29] zlibbioc_1.48.2               Rtsne_0.17                    presto_1.0.0                  purrr_1.0.2                  
 [33] RCurl_1.98-1.14               rappdirs_0.3.3                GenomeInfoDbData_1.2.11       irlba_2.3.5.1                
 [37] listenv_0.9.1                 spatstat.utils_3.0-4          goftest_1.2-3                 RSpectra_0.16-1              
 [41] spatstat.random_3.2-3         fitdistrplus_1.1-11           parallelly_1.37.1             DelayedMatrixStats_1.24.0    
 [45] leiden_0.4.3.1                codetools_0.2-20              DelayedArray_0.28.0           tidyselect_1.2.1             
 [49] farver_2.1.1                  ScaledMatrix_1.10.0           BiocFileCache_2.10.1          spatstat.explore_3.2-7       
 [53] jsonlite_1.8.8                progressr_0.14.0              ggridges_0.5.6                survival_3.5-8               
 [57] tools_4.3.3                   ica_1.0-3                     Rcpp_1.0.12                   glue_1.7.0                   
 [61] gridExtra_2.3                 SparseArray_1.2.4             DESeq2_1.42.1                 xfun_0.43                    
 [65] withr_3.0.0                   BiocManager_1.30.22           fastmap_1.1.1                 fansi_1.0.6                  
 [69] rsvd_1.0.5                    digest_0.6.35                 R6_2.5.1                      mime_0.12                    
 [73] colorspace_2.1-0              scattermore_1.2               tensor_1.5                    spatstat.data_3.0-4          
 [77] RSQLite_2.3.6                 RhpcBLASctl_0.23-42           ggsci_3.0.3                   utf8_1.2.4                   
 [81] generics_0.1.3                data.table_1.15.4             httr_1.4.7                    htmlwidgets_1.6.4            
 [85] S4Arrays_1.2.1                uwot_0.2.2                    pkgconfig_2.0.3               gtable_0.3.5                 
 [89] blob_1.2.4                    lmtest_0.9-40                 SingleCellExperiment_1.24.0   XVector_0.42.0               
 [93] htmltools_0.5.8.1             carData_3.0-5                 dotCall64_1.1-1               scales_1.3.0                 
 [97] png_0.1-8                     harmony_1.2.0                 knitr_1.46                    rstudioapi_0.16.0            
[101] reshape2_1.4.4                curl_5.2.1                    nlme_3.1-164                  zoo_1.8-12                   
[105] cachem_1.0.8                  stringr_1.5.1                 BiocVersion_3.18.1            KernSmooth_2.23-22           
[109] vipor_0.4.7                   miniUI_0.1.1.1                AnnotationDbi_1.64.1          ggrastr_1.0.2                
[113] pillar_1.9.0                  grid_4.3.3                    vctrs_0.6.5                   RANN_2.6.1                   
[117] promises_1.3.0                BiocSingular_1.18.0           car_3.1-2                     beachmat_2.18.1              
[121] dbplyr_2.5.0                  xtable_1.8-4                  cluster_2.1.6                 beeswarm_0.4.0               
[125] locfit_1.5-9.9                cli_3.6.2                     compiler_4.3.3                rlang_1.1.3                  
[129] crayon_1.5.2                  future.apply_1.11.2           ggsignif_0.6.4                labeling_0.4.3               
[133] ggbeeswarm_0.7.2              plyr_1.8.9                    stringi_1.8.3                 BiocParallel_1.36.0          
[137] viridisLite_0.4.2             deldir_2.0-4                  munsell_0.5.1                 Biostrings_2.70.3            
[141] lazyeval_0.2.2                bspm_0.5.5                    spatstat.geom_3.2-9           Matrix_1.6-5                 
[145] ExperimentHub_2.10.0          RcppHNSW_0.6.0                sparseMatrixStats_1.14.0      bit64_4.0.5                  
[149] statmod_1.5.0                 KEGGREST_1.42.0               shiny_1.8.1.1                 interactiveDisplayBase_1.40.0
[153] AnnotationHub_3.10.0          ROCR_1.0-11                   igraph_2.0.3                  broom_1.0.5                  
[157] memoise_2.0.1                 bit_4.0.5                    
RNGkind()
[1] "Mersenne-Twister" "Inversion"        "Rejection"       
LS0tCnRpdGxlOiAiVGVzdGluZyIKYXV0aG9yOiAiSm9zw6kgTWFudWVsIEfDs21leiBTaWx2YSIKZGF0ZTogImByIFN5cy5EYXRlKClgIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0KCmFsbF90aW1lcyA8LSBsaXN0KCkgIyBzdG9yZSB0aGUgdGltZSBmb3IgZWFjaCBjaHVuawprbml0cjo6a25pdF9ob29rcyRzZXQodGltZV9pdCA9IGxvY2FsKHsKICBub3cgPC0gTlVMTAogIGZ1bmN0aW9uKGJlZm9yZSwgb3B0aW9ucykgewogICAgaWYgKGJlZm9yZSkgewogICAgICBub3cgPDwtIFN5cy50aW1lKCkKICAgIH0gZWxzZSB7CiAgICAgIHJlcyA8LSBkaWZmdGltZShTeXMudGltZSgpLCBub3csIHVuaXRzID0gInNlY3MiKQogICAgICBhbGxfdGltZXNbW29wdGlvbnMkbGFiZWxdXSA8PC0gcmVzCiAgICB9CiAgfQp9KSkKCmtuaXRyOjpvcHRzX2NodW5rJHNldCgKICB0aWR5ID0gVFJVRSwKICB0aWR5Lm9wdHMgPSBsaXN0KHdpZHRoLmN1dG9mZiA9IDk1KSwKICBtZXNzYWdlID0gRkFMU0UsCiAgd2FybmluZyA9IEZBTFNFLAogIHRpbWVfaXQgPSBUUlVFLAogIGVycm9yID0gVFJVRSwKICBlY2hvID0gVFJVRSwKICBlbmdpbmUub3B0cyA9IGxpc3QoYmFzaCA9ICItbCIpCikKYGBgCgpgYGB7ciBsaWJyYXJpZXMsIGluY2x1ZGUgPSBUUlVFfQoKbGlicmFyeShTZXVyYXQpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkocGF0Y2h3b3JrKQpsaWJyYXJ5KHNjdHJhbnNmb3JtKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoZ2dwdWJyKQpsaWJyYXJ5KHRpZHlyKQpsaWJyYXJ5KGdncmVwZWwpCmxpYnJhcnkoY2VsbGRleCkgIyBDZWxsIGFubm90YXRpb24uCmxpYnJhcnkoU2luZ2xlUikgIyBDZWxsIGFubm90YXRpb24uCmxpYnJhcnkocGFyYWxsZWwpICMgZGV0ZWN0Q29yZXMoKQpsaWJyYXJ5KGZ1dHVyZSkgIyBBbGxvd3MgcGFyYWxsZWxpemF0aW9uIGluIFNldXJhdC4KbGlicmFyeShyZWFkT0RTKSAjIEFsbG93cyBvZHMgZmlsZSBpbXBvcnQgdG8gYWRkIHNhbXBsZSBpbmZvCiMgU2V0IHVwIFNldXJhdCBwYXJhcmVsbCBjb21wdXRpbmcuCm9wdGlvbnMocGFyYWxsZWxseS5mb3JrLmVuYWJsZSA9IFRSVUUpCnBsYW4oIm11bHRpY29yZSIsIHdvcmtlcnMgPSBkZXRlY3RDb3JlcygpKQpgYGAKCiMgMS4gSW50cm86IFRoZXJlIGlzIGFjdHVhbGx5IGJhdGNoIGVmZmVjdC4KCldlIHJlY2VudGx5IGZvdW5kIG91dCB0aGF0IHNvbWUgY2x1c3RlcnMgYXJlIGV4Y2x1c2l2ZWx5IGZvcm1lZCBieSBjZWxscyBvZiBhIHNpbmdsZSBydW4sIGluZGljYW50aW5nIHRoZSBwcmVzZW5jZSBvZiBiYXRjaCBlZmZlY3QuCgpgYGB7ciByZWFkX3Byb2Nlc3NlZF9kYXRhLCBpbmNsdWRlID0gRkFMU0V9CgpTQ1BfZGF0YSA8LSByZWFkUkRTKGZpbGUgPSAifi9Eb2N1bWVudHMvU0NfUHJvc3RhdGUvRGF0YS9TQ19Qcm9zdGF0ZV9wcm9jZXNzZWQucmRzIikKYGBgCgpgYGB7ciBiYXRjaF9lZmZlY3RfcGxvdCwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MzB9CgpwMSA8LSBEaW1QbG90KFNDUF9kYXRhLCByZWR1Y3Rpb24gPSAidW1hcCIsIGxhYmVsID0gVFJVRSwgcmVwZWwgPSBUUlVFLCBsYWJlbC5zaXplID0gNCkgKyB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSksIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApKSArIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gMykpKQoKcDIgPC0gRGltUGxvdChTQ1BfZGF0YSwgcmVkdWN0aW9uID0gInVtYXAiLCBsYWJlbCA9IFRSVUUsIHJlcGVsID0gVFJVRSwgbGFiZWwuc2l6ZSA9IDQsIGdyb3VwLmJ5ID0gIlNhbXBsZV9OYW1lIikgKyB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSksIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApKSArIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gMykpKQoKcDMgPC0gRGltUGxvdChTQ1BfZGF0YSwgcmVkdWN0aW9uID0gInVtYXAiLCBsYWJlbCA9IEZBTFNFLCByZXBlbCA9IFRSVUUsIGxhYmVsLnNpemUgPSA0LCBncm91cC5ieSA9ICJvcmlnLmlkZW50IikgKyB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSksIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApKSArIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gMykpKQoKcDEgKyBwMiArIHAzCmBgYApOb3RlOiBDbHVzdGVyIDQgaXMgMTAwJSBydW40IGFuZCBjbHVzdGVyIDE1IGlzIDEwMCUgcnVuIDMuIFRoZXkgb3V0cHV0IGFuIGVycm9yIGFuZCB3ZSBkb24ndCB3YW50IHRvIGV4cGVuZCBtdWNoIHRpbWUgb24gdGhpcy4KCkFzIHdlIGNhbiBzZWUgaW4gdGhlIGltYWdlLCBjbHVzdGVyIDQgYW5kIGNsdXN0ZXIgMTUgaXMgY29tcG9zZWQgZXhjbHVzaXZlbHkgb2YgY2VsbHMgZnJvbSBydW40IGFuZCBydW4zLCByZXNwZWN0aXZlbHkuIEFsc28sIGFuYWx5emluZyB0aGUgcHJvcG9ydGlvbnMgb2YgZWFjaCBydW4gdGhyb3dzIGFuIHVuZXF1YWwgZGlzdHJpYnV0aW9uIG9mIGNlbGxzIGZyb20gZWFjaCBiYXRjaC4KCmBgYHtyIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEwfQoKY2x1c3RlcnMgPC0gbGV2ZWxzKFNDUF9kYXRhJHNldXJhdF9jbHVzdGVycykKZGYgPC0gZGF0YS5mcmFtZSgpCmZvcihpIGluIDE6bGVuZ3RoKGNsdXN0ZXJzKSl7CiAgaWYgKGNsdXN0ZXJzW2ldICE9IDQgJiBjbHVzdGVyc1tpXSAhPSAxNCkgIHsKICAgICAgICBjdXJfZGYgPC0gYXMuZGF0YS5mcmFtZShTQ1BfZGF0YUBtZXRhLmRhdGEgJT4lIHN1YnNldChzZXVyYXRfY2x1c3RlcnMgPT0gY2x1c3RlcnNbaV0pICU+JSAuJG9yaWcuaWRlbnQgJT4lIHRhYmxlKCkgLwogICAgdGFibGUoU0NQX2RhdGEkb3JpZy5pZGVudCkpCiAgCiAgICBjdXJfZGYkRnJlcSA8LSBjdXJfZGYkRnJlcSAqIDEvKHN1bShjdXJfZGYkRnJlcSkpCiAgCiAgICBjdXJfZGYkY2x1c3RlciA8LSBjbHVzdGVyc1tpXQogICAgZGYgPC0gcmJpbmQoZGYsIGN1cl9kZikKICB9IGVsc2UgewogICAgY3VyX2RmIDwtIGFzLmRhdGEuZnJhbWUoU0NQX2RhdGFAbWV0YS5kYXRhICU+JSBzdWJzZXQoc2V1cmF0X2NsdXN0ZXJzID09IGNsdXN0ZXJzW2ldKSAlPiUgLiRvcmlnLmlkZW50ICU+JSB0YWJsZSgpKQogIAogICAgY3VyX2RmJEZyZXEgPC0gY3VyX2RmJEZyZXEgKiAxLyhzdW0oY3VyX2RmJEZyZXEpKQogIAogICAgY3VyX2RmJGNsdXN0ZXIgPC0gY2x1c3RlcnNbaV0KICAgIGRmIDwtIHJiaW5kKGRmLCBjdXJfZGYpCiAgfQp9CgoKUnVuRnJlcS5ub0ludCA8LSBnZ3Bsb3QoZGYsIGFlcyh5PUZyZXEsIHg9Y2x1c3RlciwgZmlsbD0uKSkgKwogIGdlb21fYmFyKHN0YXQ9J2lkZW50aXR5JykgKwogIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBjKDAsMCkpICsKICB5bGFiKCdub3JtYWxpemVkIHByb3BvcnRpb24nKSArCiAgdGhlbWUoCiAgICBwYW5lbC5ncmlkLm1ham9yPWVsZW1lbnRfYmxhbmsoKSwKICAgIHBhbmVsLmdyaWQubWlub3I9ZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGU9NDUsIGhqdXN0PTEpLAogICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLAogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy5saW5lLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICBheGlzLmxpbmUueCA9IGVsZW1lbnRfYmxhbmsoKQogICkKUnVuRnJlcS5ub0ludApgYGAKCldlIGFsc28gcmUtdmlzdWFsaXplIHRoZSBQQ0EgcGxvdDoKCmBgYHtyIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEwfQoKSWRlbnRzKFNDUF9kYXRhKSA8LSAib3JpZy5pZGVudCIKRGltUGxvdChTQ1BfZGF0YSwgcmVkdWN0aW9uID0gInBjYSIpCmBgYAoKIyAyLiBJbnRyb2R1Y3Rpb24gdG8gZGF0YSBpbnRlZ3JhdGlvbiB3aXRoIFNldXJhdC4KClNldXJhdCBvZmZlcnMgbWV0aG9kcyB0byBpbnRlZ3JhdGUgZGF0YSBmcm9tIGRpZmZlcmVudCBiYXRjaGVzIChkaWZmZXJlbnQgc2VxdWVuY2luZyBydW5zLCBkaWZmZXJlbnQgc2FtcGxlcywgZXRjLikuIEluIHY1LCBhIG5ldyBtZXRob2QgY2FsbGVkIEludGVncmF0ZUxheWVycyB0aGV5IGVhc2lseSBwZXJmb3JtIHRoZSB3aG9sZSBwaXBlbGluZSBpbiBhIGZldyBzdGVwcy4gVGhlIGZpcnN0IG9mIHRoZW0gaXMgdG8gc3BsaXQgdGhlIGRhdGEgYWNjb3JkaW5nIHRvIHRoZSBzb3VyY2Ugb2YgYmF0Y2ggZWZmZWN0IChpbiBvdXIgY2FzZSBieSBydW4pLgoKYGBge3IgcmVhZF9yYXdfZGF0YSwgaW5jbHVkZT1GQUxTRX0KClNDUF9kYXRhIDwtIHJlYWRSRFMoZmlsZSA9ICJ+L0RvY3VtZW50cy9TQ19Qcm9zdGF0ZS9EYXRhL1NDX1Byb3N0YXRlX3Jhdy5yZHMiKQpgYGAKCmBgYHtyIHNwbGl0X2RhdGF9CgojIFRoZSBzcGxpdCBtZXRob2Qgc3BsaXRzIHRoZSBnaXZlbiBzbG90IGFjY29yZGluZyB0byB0aGUgaW5kaWNhdGVkIGluZm9ybWF0aW9uLgpTQ1BfZGF0YVtbIlJOQSJdXSA8LSBzcGxpdChTQ1BfZGF0YVtbIlJOQSJdXSwgZiA9IFNDUF9kYXRhJG9yaWcuaWRlbnQpCmBgYAoKIyAyLjEuIE5vcm1hbGl6ZSBhbmQgYXBwbHkgZGF0YSBpbnRlZ3JhdGlvbi4KCkl0IGlzIG5lY2Vzc2FyeSB0byBub3JtYWxpemUgdGhlIGRhdGEgYmVmb3JlIGludGVncmF0aW9uLiBBY2NvcmRpbmcgdG8gbWFpbnRhaW5lcnMgKGh0dHBzOi8vZ2l0aHViLmNvbS9zYXRpamFsYWIvc2V1cmF0L2lzc3Vlcy80ODExKSBpdCBkb2Vzbid0IG1pbmQgdG8gbm9ybWFsaXplIGJlZm9yZSBvciBhZnRlciBzcGxpdHRpbmcuCgpTaW5jZSByZWNlbnQgZGlzY3Vzc2lvbiBpbmRpY2F0ZXMgdGhhdCBhY2NvcmRpbmcgdG8gdGhlIHVzZSBjYXNlIHNvbWV0aW1lcyBpcyBiZXR0ZXIgdG8gd29yayBvbiByYXcsIG5vbi1pbnRlZ3JhdGVkIHZhbHVlcyAoaHR0cHM6Ly9naXRodWIuY29tL3NhdGlqYWxhYi9zZXVyYXQvZGlzY3Vzc2lvbnMvNTQ1Mj91dG1fc291cmNlPXBvY2tldF9zYXZlcyksIHdlIGFsc28gcGVyZm9ybSB0aGUgc3RhbmRhcmQgbm9ybWFsaXphdGlvbiB3b3JrZmxvdy4KCmBgYHtyIG5vcm1fc3RkLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD0xMH0KCiMgU3RhbmRhcmQgbm9ybWFsaXphdGlvbi4KU0NQX2RhdGEgPC0gTm9ybWFsaXplRGF0YShTQ1BfZGF0YSkKU0NQX2RhdGEgPC0gRmluZFZhcmlhYmxlRmVhdHVyZXMoU0NQX2RhdGEsIG5mZWF0dXJlcyA9IDMwMDApClNDUF9kYXRhIDwtIFNjYWxlRGF0YShTQ1BfZGF0YSkKYGBgCgpXZSBub3cgcnVuIFNDVHJhbnNmb3JtLCBQQ0EgYW5kIHRoZSBpbnRlZ3JhdGlvbi4KCmBgYHtyIGJhdGNoX2VmZmVjdF9zY3QsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEwfQoKIyBMYXVuY2ggc2N0IHRyYW5zZm9ybSBhbmQgcnVuIFBDQS4KU0NQX2RhdGEgPC0gU0NUcmFuc2Zvcm0oU0NQX2RhdGEsIHZzdC5mbGF2b3IgPSAidjIiLCB2YXJzLnRvLnJlZ3Jlc3MgPSAicGVyY2VudC5tdCIpClNDUF9kYXRhIDwtIFJ1blBDQShTQ1BfZGF0YSwgYXNzYXkgPSAiU0NUIikKCiMgSW50ZWdyYXRpb24uClNDUF9kYXRhIDwtIEludGVncmF0ZUxheWVycygKICBvYmplY3QgPSBTQ1BfZGF0YSwgbWV0aG9kID0gSGFybW9ueUludGVncmF0aW9uLAogIG5vcm1hbGl6YXRpb24ubWV0aG9kID0gIlNDVCIsCiAgdmVyYm9zZSA9IEZBTFNFCikKYGBgCgpUaGVyZSBhcmUgc2V2ZXJhbCBtZXRob2RzIGZvciBpbnRlZ3JhdGlvbiwgYnV0IGFjY29yZGluZyB0byBzb21lIHNvdXJjZXMgKGh0dHBzOi8vZ2Vub21lYmlvbG9neS5iaW9tZWRjZW50cmFsLmNvbS9hcnRpY2xlcy8xMC4xMTg2L3MxMzA1OS0wMTktMTg1MC05KSwgdGhlIGJlc3Qgb25lcyBhcmUgSGFybW9ueSwgU2V1cmF0J3MgQ0NBIGFuZCBzY1ZJSSAocmVxdWlyZXMgc2V0dGluZyB1cCBhIGNvbmRhIGVudmlyb25tZW50IGFuZCBpbnN0YWxsaW5nIHJldGljdWxhdGUsIHNlZSBkb2N1bWVudGF0aW9uKS4gV2UgY2hvb3NlIEhhcm1vbnkgZm9yIGJlaW5nIHdlbGwtaW50ZWdyYXRlZCB3aXRoIFNlcnVhdCwgYW5kIHBlcmZvcm1pbmcgcHJldHR5IHdlbGwgd2l0aCBsb3cgY29tcHV0YXRpb25hbCBlZmZvcnQuCgpJZiB3ZSByZS12aXN1YWxpemUgdGhlIFBDQSBwbG90LCB3ZSBhcHByZWNpYXRlIGEgYmlnZ2VyIG92ZXJsYXAgYmV0d2VlbiBydW5zLgoKYGBge3IgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTB9CgpJZGVudHMoU0NQX2RhdGEpIDwtICJvcmlnLmlkZW50IgpEaW1QbG90KFNDUF9kYXRhLCByZWR1Y3Rpb24gPSAicGNhIikKYGBgCgojIyAyLjIuIFNldCBkaW1lbnNpb25hbGl0eS4KCldoaWxlIHRoZSBlbGJvdyBhcHBlYXJzIGFyb3VuZCB0aGUgMTV0aCBQQywgd2UgZXh0ZW5kIHRoZSBpbmNsdWRlZCBQQ3MgdXAgdG8gdGhlIDMwdGggZm9sbG93aW5nIHRoZSBuZXcgZ3VpZGVsaW5lcyBieSB0aGUgU2V1cmF0IGRldmVsb3BlcnMgYWZ0ZXIgU0NUcmFuc2Zvcm0gbm9ybWFsaXphdGlvbiBpbXBsZW1lbnRhdGlvbi4KCmBgYHtyIGVsYndvbF9wbG90LCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD0xMH0KCkVsYm93UGxvdChTQ1BfZGF0YSwgbmRpbXMgPSA1MCwgcmVkdWN0aW9uID0gInBjYSIpICMgY2hvb3NlIDMwCmBgYAoKVGhlIGhlYXRtYXAgYW5kIHRoZSBmZWF0dXJlIHBsb3QgZ2l2ZSB1cyBpbmZvcm1hdGlvbiBhYm91dCB0aGUgc2lnbmlmaWNhbmNlIGFuZCBjb21wb3NpdGlvbiBvZiBlYWNoIFBDLgoKYGBge3IgUENBX2hlYXRtYXAsIGZpZy5oZWlnaHQ9MTUsIGZpZy53aWR0aD0xMH0KCkRpbUhlYXRtYXAoU0NQX2RhdGEsIGRpbXMgPSAxOjMwLCBiYWxhbmNlZCA9IFRSVUUsIHJlZHVjdGlvbiA9ICJwY2EiKQpgYGAKCmBgYHtyIFBDQV90b3BfZmVhdHVyZXMsIGZpZy5oZWlnaHQ9MzAsIGZpZy53aWR0aD0xNX0KClZpekRpbUxvYWRpbmdzKFNDUF9kYXRhLCBkaW1zID0gMTozMCwgcmVkdWN0aW9uID0gInBjYSIpCmBgYAoKIyAzLiBGaW5kIHZhcmlhYmxlIHRvcCB2YXJpYWJsZSBmZWF0dXJlcy4KCldBUklORzogIFNpbmNlIHRoZSBkYXRhIGlzIHNwbGl0dGVkIGludG8gNCBsYXllcnMsIGlzIG5vdCBwb3NzaWJsZSB0byBwbG90IHRoZSB0b3AgdmFyaWFibGUgZ2VuZXMsIGJ1dCB3ZSBzdGlsbCBjYW4gcnVuIEZpbmRWYXJpYWJsZUZlYXR1cmVzIGFuZCBhY2Nlc3MgdGhlIGxpc3QgdXNpbmcgVmFyaWFibGVGZWF0cnVlcy4gCgpgYGB7ciB2YXJfZmVhdHVyZXMsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEwfQoKIyBTQ1BfZGF0YSA8LSBGaW5kVmFyaWFibGVGZWF0dXJlcyhTQ1BfZGF0YSwgc2VsZWN0aW9uLm1ldGhvZCA9ICJ2c3QiLCBuZmVhdHVyZXMgPSAzMDAwLCBhc3NheSA9ICJTQ1QiKQoKIyBHZW5lcyB3aXRoIGRpZmZlcmVudGlhbCBleHByZXNzaW9uIGluIGRpZmZlcmVudCBjZWxscyBhcmUgZ29vZCBjYW5kaWRhdGVzIHRvIGJlIGJpb21hcmtlcnMuCiMgSWRlbnRpZnkgdGhlIDIwIG1vc3QgaGlnaGx5IHZhcmlhYmxlIGdlbmVzCnRvcCA8LSBoZWFkKFZhcmlhYmxlRmVhdHVyZXMoU0NQX2RhdGEsIGFzc2F5ID0gIlNDVCIsbGF5ZXIgPSBydW4pLCAyMCkKYGBgCgojIDQuIENsdXN0ZXJpbmcuCgpDbHVzdGVyaW5nIHJlc29sdXRpb24gZmluZS10dW5pbmcgaXMgcGVyZm9ybWVkIGJ5IGEgc2VwYXJhdGVkIC5SbWQgZmlsZSAoUmVzb2x1dGlvbiBmaW5lLXR1bmluZy5SbWQpLCBnaXZpbmcgMC44IGFzIGEgYXBwcm9wcmlhdGUgdmFsdWUgZm9yIGNsdXN0ZXJpbmcuCgpJdCBpcyBpbXBvcnRhbnQgdG8gbm90aWNlIHRoYXQgYSBuZXcgcmVkdWN0aW9uIGlzIGNyZWF0ZWQgY2FsbGVkICJoYXJtb255Ii4gV2UgbmVlZCB0byBpbmRpY2F0ZSB0aGlzIGFzIHRoZSByZWR1Y3Rpb24gdG8gdXNlIGluIHRoZSBjbHVzdGVyaW5nLgoKYGBge3IgY2x1c3RlcmluZ30KCiMgUmVzb2x1dGlvbiBmaW5lLXR1bmVkIGluIGEgc2VwYXJhdGUgUm1kLgpTQ1BfZGF0YSA8LSBGaW5kTmVpZ2hib3JzKFNDUF9kYXRhLCBkaW1zID0gMTozMCwgcmVkdWN0aW9uID0gImhhcm1vbnkiKQpTQ1BfZGF0YSA8LSBGaW5kQ2x1c3RlcnMoU0NQX2RhdGEsIHJlc29sdXRpb24gPSAwLjgsICkgIyBEZWZhdWx0IHJlc29sdXRpb24gPSAwLjgKU0NQX2RhdGEgPC0gUnVuVU1BUChTQ1BfZGF0YSwgZGltcyA9IDE6MzAsIHJlZHVjdGlvbiA9ICJoYXJtb255IikKYGBgCgpXZSBub3cgYXBwcmVjaWF0ZSBhIG1vcmUgaG9tb2dlbmVvdXMgZGlzdHJpYnV0aW9uIG9mIHRoZSBjZWxscyBmcm9tIGVhY2ggcnVuIGFtb25nIHRoZSBjbHVzdGVyczoKCmBgYHtyIGNsdXN0ZXJfdmlzdWFsaXphdGlvbiwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MzB9CgpwMSA8LSBEaW1QbG90KFNDUF9kYXRhLCByZWR1Y3Rpb24gPSAidW1hcCIsIGxhYmVsID0gVFJVRSwgcmVwZWwgPSBUUlVFLCBsYWJlbC5zaXplID0gNCkgKyB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSksIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApKSArIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gMykpKQoKcDIgPC0gRGltUGxvdChTQ1BfZGF0YSwgcmVkdWN0aW9uID0gInVtYXAiLCBsYWJlbCA9IFRSVUUsIHJlcGVsID0gVFJVRSwgbGFiZWwuc2l6ZSA9IDQsIGdyb3VwLmJ5ID0gIlNhbXBsZV9OYW1lIikgKyB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSksIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApKSArIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gMykpKQoKcDMgPC0gRGltUGxvdChTQ1BfZGF0YSwgcmVkdWN0aW9uID0gInVtYXAiLCBsYWJlbCA9IEZBTFNFLCByZXBlbCA9IFRSVUUsIGxhYmVsLnNpemUgPSA0LCBncm91cC5ieSA9ICJvcmlnLmlkZW50IikgKyB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSksIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApKSArIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gMykpKQoKcDEgKyBwMiArIHAzCmBgYAoKYGBge3IgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTB9CmNsdXN0ZXJzIDwtIGxldmVscyhTQ1BfZGF0YSRzZXVyYXRfY2x1c3RlcnMpCmRmIDwtIGRhdGEuZnJhbWUoKQpmb3IoaSBpbiAxOmxlbmd0aChjbHVzdGVycykpewogICAgICBjdXJfZGYgPC0gYXMuZGF0YS5mcmFtZShTQ1BfZGF0YUBtZXRhLmRhdGEgJT4lIHN1YnNldChzZXVyYXRfY2x1c3RlcnMgPT0gY2x1c3RlcnNbaV0pICU+JSAuJG9yaWcuaWRlbnQgJT4lIHRhYmxlKCkgLwogIHRhYmxlKFNDUF9kYXRhJG9yaWcuaWRlbnQpKQoKICBjdXJfZGYkRnJlcSA8LSBjdXJfZGYkRnJlcSAqIDEvKHN1bShjdXJfZGYkRnJlcSkpCgogIGN1cl9kZiRjbHVzdGVyIDwtIGNsdXN0ZXJzW2ldCiAgZGYgPC0gcmJpbmQoZGYsIGN1cl9kZikKfQoKUnVuRnJlcS5JbnQgPC0gZ2dwbG90KGRmLCBhZXMoeT1GcmVxLCB4PWNsdXN0ZXIsIGZpbGw9LikpICsKICBnZW9tX2JhcihzdGF0PSdpZGVudGl0eScpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLDApKSArCiAgeWxhYignbm9ybWFsaXplZCBwcm9wb3J0aW9uJykgKwogIHRoZW1lKAogICAgcGFuZWwuZ3JpZC5tYWpvcj1lbGVtZW50X2JsYW5rKCksCiAgICBwYW5lbC5ncmlkLm1pbm9yPWVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTQ1LCBoanVzdD0xKSwKICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMubGluZS55ID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy5saW5lLnggPSBlbGVtZW50X2JsYW5rKCkKICApClJ1bkZyZXEuSW50CmBgYAoKUHJvcG9ydGlvbnMgYXJlIGEgYml0IG1vcmUgZXF1aWxpYnJhdGVkIG5vdy4KCmBgYHtyfQoKUnVuRnJlcS5ub0ludCArIFJ1bkZyZXEuSW50CmBgYAoKIyMgNC4xLiBDbHVzdGVyIFFDLgoKQ2x1c3RlciBRQyBzaG93cyBob21vZ2VuZW91cyBjaGFyYWN0ZXJpc3RpY3MgYWNyb3NzIHRoZSBjbHVzdGVycyB3aXRoIHRoZSBleGNlcHRpb24gb2YgY2x1c3RlciAyMiAoYWJub3JtYWwgbG93IG51bWJlciBvZiBmZWF0dXJlcykuIERlc3BpdGUgd2hhdCBpdCBtaWdodCBsb29rIGxpa2UsIHRoaXMgYWN0dWFsbHkgY29uZm9ybXMgYW5kIGFkdmFudGFnZSwgYXMgaWYgdGhhdCBzcGVjaWZpYyBncm91cCBvZiBjZWxscyBnaXZlIGluY29uc2lzdGVudCByZXN1bHRzLCBiZWNhdXNlIHRoZXkgaGF2ZSBiZWVuIGlzb2xhdGVkIGluIHRoZWlyIG93biBjbHVzdGVyIHdlIGNhbiBtb3ZlIGZvcndhcmQganVzdCBpZ25vcmluZyBvciByZW1vdmluZyBpdC4KCmBgYHtyIGNsdXN0ZXJfUUMsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEwfQoKIyBWaXN1YWxpemUgUUMgbWV0cmljcyBhcyBhIHZpb2xpbiBwbG90ClZsblBsb3QoU0NQX2RhdGEsIGZlYXR1cmVzID0gYygibkZlYXR1cmVfUk5BIiwgIm5Db3VudF9STkEiLCAicGVyY2VudC5tdCIpLCBuY29sID0gMykgKyBOb0xlZ2VuZCgpCgojIFpvb20gaW4gb24gbkZlYXR1cmVfUk5BIHZpb2xpbiBwbG90LgpWbG5QbG90KFNDUF9kYXRhLCBmZWF0dXJlcyA9ICJuRmVhdHVyZV9STkEiLCBuY29sID0gMSkgKyB5bGltKDAsIDI1MDApICsgTm9MZWdlbmQoKQoKIyBWaXN1YWxpemUgcmVsYXRpb25zaGlwcyBpbiBtZXRhZGF0YSB0byBkZXRlY3Qgb3V0bGllcnMgd2l0aCBGZWF0dXJlU2NhdHRlciBmdW5jdGlvbgpwbG90MSA8LSBGZWF0dXJlU2NhdHRlcihTQ1BfZGF0YSwgZmVhdHVyZTEgPSAibkNvdW50X1JOQSIsIGZlYXR1cmUyID0gInBlcmNlbnQubXQiKQpwbG90MiA8LSBGZWF0dXJlU2NhdHRlcihTQ1BfZGF0YSwgZmVhdHVyZTEgPSAibkNvdW50X1JOQSIsIGZlYXR1cmUyID0gIm5GZWF0dXJlX1JOQSIpCnBsb3QxICsgTm9MZWdlbmQoKSArIHBsb3QyICsgTm9MZWdlbmQoKQpgYGAKCiMgNS4gQW5ub3RhdGlvbi4KCiMjIDUuMS4gQnktY2VsbCBhbm5vdGF0aW9uLgoKQ2VsbC1ieS1jZWxsIGFubm90YXRpb24gaWRlbnRpZmllcyAzMCBkaWZmZXJlbnQgY2VsbCB0eXBlcyBiYXNlZCBvbiB0aGUgSHVtYW5QcmltYXJ5Q2VsbEF0bGFzLCB3aGljaCBkaXN0cmlidXRpb24gcHJldHR5IG11Y2ggY29pbmNpZGVzIHdpdGggdGhlIGNsdXN0ZXIgbGF5b3V0LgoKRm9yIHRoaXMgc3RlcCwgd2Ugbm93IG5lZWQgdG8gam9pbiB0aGUgbGF5ZXJzIGJlZm9yZSBleHBvcnRpbmcgdG8gYSBTQ0V4cGVyaW1lbnQgb2JqZWN0LgoKYGBge3IgYW5ub3RhdGlvbn0KCiMgVXNpbmcgY2VsbGRleCBhbmQgU2luZ2xlUiBwYWNrYWdlcy4KIyBEb3dubG9hZCByZWZlcmVuY2UgZGF0YSBmcm9tIGNlbGxkZXguCnJlZmVyZW5jZSA8LSBIdW1hblByaW1hcnlDZWxsQXRsYXNEYXRhKCkKCiMgSm9pbiBsYXllcnMgYmVmb3JlIGNvbnZlcnNpb24uIFNpbmdsZVIgdXNlcyB0aGUgUk5BIGFzc2F5LgptZXJnZWQuU0NleHAgPC0gSm9pbkxheWVycyhTQ1BfZGF0YSwgYXNzYXkgPSAiUk5BIikgCgojIENvbnZlcnQgU2V1cmF0IG9iamVjdCBpbnRvIGEgU2luZ2xlQ2VsbEV4cGVyaW1lbnQgT2JqZWN0IGZvciBTaW5nbGVSIGlucHV0LgptZXJnZWQuU0NleHAgPC0gYXMuU2luZ2xlQ2VsbEV4cGVyaW1lbnQobWVyZ2VkLlNDZXhwKQoKU2luZ2xlUi5hbm5vdGF0aW9uIDwtIFNpbmdsZVIodGVzdCA9IG1lcmdlZC5TQ2V4cCwgcmVmID0gcmVmZXJlbmNlLCBhc3NheS50eXBlLnRlc3QgPSAibG9nY291bnRzIiwgbGFiZWxzID0gcmVmZXJlbmNlJGxhYmVsLm1haW4sIG51bS50aHJlYWRzID0gZGV0ZWN0Q29yZXMoKSkKClNDUF9kYXRhW1siY2VsbC5sYWJlbHMiXV0gPC0gU2luZ2xlUi5hbm5vdGF0aW9uJGxhYmVscwpgYGAKCmBgYHtyIGFubm90YXRpb25fdmlzX2NlbGwsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEwfQoKRGltUGxvdChTQ1BfZGF0YSwgcmVkdWN0aW9uID0gInVtYXAiLCBncm91cC5ieSA9ICJjZWxsLmxhYmVscyIsIGxhYmVsID0gVFJVRSwgcmVwZWwgPSBUUlVFLCBsYWJlbC5zaXplID0gNCkgKyB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSksIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApKSArIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gMykpKQpgYGAKCiMjIDUuMi4gQnktY2x1c3RlciBhbm5vdGF0aW9uLgoKV2UgY3JlYXRlIG91ciBvd24gY29tcG9zaXRlIGNsdXN0ZXIgbmFtZXMgYnkgYWRkaW5nIHRoZSBjbHVzdGVyIGFubm90YXRpb24gdG8gdGhlIGNsdXN0ZXIgbnVtYmVyIHByb3ZpZGVkIGJ5IFN1ZXJhdC4gVGh1cywgd2hhdCB3ZSBzZWUgaXMgYW4gZXN0aW1hdGlvbiBvZiB0aGUgY2VsbCB0eXBlIHRoYXQgYmV0dGVyIGZpdHMgdGhlIGdlbmV0aWMgbGFuZHNjYXBlIG9mIGVhY2ggY2x1c3Rlci4KCmBgYHtyIGNsdXN0ZXJfYW5ub3RhdGlvbn0KCiMgT2J0YWluaW5nIGEgdmVjdG9yIGNvbnRhaW5pbmcgdGhlIGNsdXN0ZXIgb2YgZWFjaCBjZWxsIGluIG9yZGVyLgoKIyBHZXQgdGhlIGZhY3RvciBjb250YWluZWQgaW4gdGhlIFNldXJhdE9iamVjdCB3aXRoIGFsbCB0aGlzIGluZm9ybWF0aW9uLgpjbHVzdGVycyA8LSBTQ1BfZGF0YUBtZXRhLmRhdGFbWyJzZXVyYXRfY2x1c3RlcnMiXV0KCiMgVGhlIGNsdXN0ZXIgaW5mb3JtYXRpb24gZm9yIGVhY2ggY2VsbCBpcyBjb250YWluIGFzIGEgZmFjdG9yIHdoaWNoIGxldmVscyBjb2luY2lkZSB3aXRoIHRoZSB0b3RhbCBudW1iZXIgb2YgY2x1c3RlcnMgZm91bmQgYnkgRmluZENsdXN0ZXJzKCkuIEFuIGFwcHJvYWNoIHRvIHRyYW5zZm9ybSB0aGlzIGZhY3RvciBpbnRvIGEgY2hhcmFjdGVyIHZlY3RvciBpcyB0aGUgZm9sbG93aW5nOgojIE9idGFpbiB0aGUgbGlzdCBvZiBjbHVzdGVycyB3aXRoIGxldmVscyhjbHVzdGVycykuIFRoaXMgb3V0cHV0cyBhIGNoYXJhY3RlciB2ZWN0b3IgY29udGFpbmluZyB0aGUgbGV2bGVzIG9mIHRoZSBmYWN0b3IuIEFmdGVyIHRoYXQsIHdlIHVzZSB0aGUgZmFjdG9yIGl0c2VsZiBhcyBhbiBpbmRleCB0byBhY2Nlc3MgdGhlIGxldmVscyB2ZWN0b3IuIFdoZW4gdXNpbmcgYSBmYWN0b3IgYXMgYW4gaW5kZXgsIFIgZG9lcyBub3QgdXNlIHRoZSBsYWJlbHMgaXRzZWxmICh3aGljaCBpbiB0aGlzIGNhc2UgYXJlIHN0cmluZywgc28gaWYgdXNlZCBhcyBpbmRleGVzIHdvdWxkIGNhdXNlIGFuIGVycm9yKSwgYnV0IHRoZSBpbnRlcm5hbCBudW1lcmljIGluZGV4IHRoZSBmYWN0b3IgY29udGFpbnMuIFRoYXQgd2F5LCBmb3IgZWFjaCBjbHVzdGVyIGxhYmVsIGFzc29jaWF0ZWQgd2l0aCBhIGNlbGwgaW4gdGhlIGZhY3Rvciwgd2UgYWNjZXNzIGl0cyBudW1lcmljIGluZGV4IGFuZCBtYXAgaXQgdG8gdGhlIGxldmVscyB2ZWN0b3JzICh3aGljaCBjb2luY2lkZXMpLCB0aHVzIG9idGFpbmluZyBlYWNoIGNlbGwgbGFiZWwgYXMgYW4gdW5pcXVlIGNoYXJhY3RlciB2YWx1ZS4gRWFjaCBjZWxsIGxhYmVsIGlzIHRoZW4gc3RvcmFnZSBhcyBhIGNoYXJhY3RlciAodGhlIGFzLmNoYXJhY3RlciBpcyBhZGRlZCBhcyBhIGNvbnRyb2wgbWV0aG9kIHNpbmNlIFNpbmdsZVIgb25seSBhZG1pdHMgc3RyaW5ncyBhcyBsYWJlbHMpIGluIGEgdmVjdG9yLiBUaGUgdmVjdG9yIGNvbnRhaW5zIHRoZSBjbHVzdGVyIGxhYmVsIGZvciBlYWNoIGNlbGwgYXMgYSBjaGFyYWN0ZXIgdmFsdWUgaW4gdGhlIHNhbWUgb3JkZXIgYXMgZWFjaCBjZWxsIGFwcGVhcnMgaW4gdGhlIGRhdGFzZXQsIHNvIHRoZSBieS1jbHVzdGVyIGFubm90YXRpb24gZG9lc24ndCBhc3NpZ24gdGhlIGNlbGxzIHRvIGFuIGluY29ycmVjdCBjbHVzdGVyLgpjbHVzdGVycyA8LSBhcy5jaGFyYWN0ZXIobGV2ZWxzKGNsdXN0ZXJzKVtjbHVzdGVyc10pCgojIHJlZmVyZW5jZSA8LSBIdW1hblByaW1hcnlDZWxsQXRsYXNEYXRhKCkKCiMgbWVyZ2VkLlNDZXhwIDwtIGFzLlNpbmdsZUNlbGxFeHBlcmltZW50KFNDUF9kYXRhKQoKIyBXZSBpbnB1dCB0aGUgY2x1c3RlciB2ZWN0b3IgdXNpbmcgdGhlIGNsdXN0ZXJzIHBhcmFtZXRlci4KU2luZ2xlUi5hbm5vdGF0aW9uIDwtIFNpbmdsZVIodGVzdCA9IG1lcmdlZC5TQ2V4cCwgcmVmID0gcmVmZXJlbmNlLCBhc3NheS50eXBlLnRlc3QgPSAibG9nY291bnRzIiwgbGFiZWxzID0gcmVmZXJlbmNlJGxhYmVsLm1haW4sIGNsdXN0ZXJzID0gY2x1c3RlcnMsIG51bS50aHJlYWRzID0gZGV0ZWN0Q29yZXMoKSkKClNDUF9kYXRhW1siY2x1c3Rlci5sYWJlbHMiXV0gPC0gU2luZ2xlUi5hbm5vdGF0aW9uJGxhYmVscwpgYGAKCmBgYHtyIHNldF9pZHN9CgojIFdlIGNvbXBvc2l0ZSB0aGUgY2x1c3RlciBuYW1lLiBUaGF0IHdheSB3aGVuIDIgY2x1c3RlcnMnIG5hbWVzIGFyZSB0aGUgc2FtZSBTZXVyYXQgZG9lc24ndCBtZXJnZSB0aGUgbGFiZWxzLgoKIyBHZXQgY2x1c3RlcnMgbGV2ZWxzIGFjY2Vzc2luZyB0aGUgU2V1cmF0T2JqZWN0IHZhcmlhYmxlIGFzIGEgZGYgYW5kIHRoZW4gYWNjZXNzaW5nIHRoZSBkZiBhcyBhIGNvbHVtbi4KY2x1c3Rlcl9udW1iZXIgPC0gbGV2ZWxzKFNDUF9kYXRhW1sic2V1cmF0X2NsdXN0ZXJzIl1dWzEsIF0pCgojIEdldCBhbm5vdGF0aW9uIGxhYmVscy4KY2x1c3Rlcl9hbm5vdGF0aW9uIDwtIFNpbmdsZVIuYW5ub3RhdGlvbiRsYWJlbHMKCiMgU2luY2UgY2x1c3RlciBsZXZlbHMgYW5kIGxhYmVscyBhcmUgaW4gdGhlIHNhbWUgb3JkZXIsIHdlIGNvbXBvc2l0ZSB0aGUgbmV3IG5hbWVzIHVzaW5nIHBhc3RlMCAoc29ydCBvZiBlcXVpdmFsZW50IHRvIGZzdHJpbmdzIGluIHB5dGhvbikuCm5ldy5jbHVzdGVycy5pZHMgPC0gcGFzdGUwKGNsdXN0ZXJfbnVtYmVyLCAiLSIsIGNsdXN0ZXJfYW5ub3RhdGlvbikKCiMgQWRkIG5hbWVzIHRvIGVhY2ggdmFsdWUgb2YgdGhlIGNsdXN0ZXJzIGlkIHZlY3RvciBzbyBTZXVyYXQgY2FuIHRha2UgaXQgYXMgYSB2YWxpZCBpbnB1dCBmb3IgUmVuYW1lSWRlbnRzLgpuYW1lcyhuZXcuY2x1c3RlcnMuaWRzKSA8LSBsZXZlbHMoU0NQX2RhdGEpClNDUF9kYXRhIDwtIFJlbmFtZUlkZW50cyhTQ1BfZGF0YSwgbmV3LmNsdXN0ZXJzLmlkcykKU0NQX2RhdGFbWyJjZWxsLmNsdXN0ZXIubGFiZWxzIl1dIDwtIElkZW50cyhTQ1BfZGF0YSkKYGBgCgpgYGB7ciBjbHVzdGVyX2Fubm90YXRpb25fdmlzLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD0xMH0KCkRpbVBsb3QoU0NQX2RhdGEsIHJlZHVjdGlvbiA9ICJ1bWFwIiwgbGFiZWwgPSBUUlVFLCByZXBlbCA9IFRSVUUsIGxhYmVsLnNpemUgPSA0KSArIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE1KSwgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCkpICsgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSAzKSkpCmBgYAoKIyA2LiBFeHBsb3JhdG9yeSBhbmFseXNpcy4KCkhlcmUsIHdlIHN0YXJ0IHRoZSBtb3JlIGRlZXAgYW5kIGFjY3VyYXRlIGFuYWx5c2lzIG9mIHRoZSBkYXRhc2V0LgoKV2UgcmVwZWF0IHRoaXMgYW5hbHlzaXMgdG8gZm9sbG93IHRoZSBuZXcgZ3VpZGVsaW5lcyBwcm92aWRlZCBoZXJlOiBodHRwczovL3NhdGlqYWxhYi5vcmcvc2V1cmF0L2FydGljbGVzL3BhcnNlYmlvX3NrZXRjaF9pbnRlZ3JhdGlvbgoKQXMgcmVjb21tZW5kZWQgYnkgU29uZXNvbiBldCBhbGwuIGFuZCBDcm93ZWxsIGV0IGFsLiwgd2UgdXNlIGFuIGFnZ3JlZ2F0aW9uLWJhc2VkIChwc2V1ZG9idWxrKSB3b3JrZmxvdyB1c2luZyB0aGUgcmF3IGNvdW50cy4gV2UgYWdncmVnYXRlIGFsbCBjZWxscyB3aXRoaW4gdGhlIHNhbWUgY2VsbCB0eXBlIGFuZCBzYW1wbGUgdXNpbmcgdGhlIEFnZ3JlZ2F0ZUV4cHJlc3Npb24gZnVuY3Rpb24uIFRoaXMgcmV0dXJucyBhIFNldXJhdCBvYmplY3Qgd2hlcmUgZWFjaCDigJhjZWxs4oCZIHJlcHJlc2VudHMgdGhlIHBzZXVkb2J1bGsgcHJvZmlsZSBvZiBvbmUgY2VsbCB0eXBlIGluIG9uZSBpbmRpdmlkdWFsLgoKIyMgNi4xLiBGaW5kaW5nIGNsdXN0ZXIgZW5yaWNoZWQgaW4gVCBzYW1wbGVzLgoKRmlyc3QsIHdlIHdvdWxkIHRha2UgYSBsb29rIGF0IHRoZSBwcm9wb3J0aW9uIG9mIGNlbGxzIGZyb20gdGhlIGRpZmZlcmVudCBncm91cHMgKFQsIE4sIE5BVCBhbmQgQVQpIG9uIGVhY2ggY2x1c3Rlci4KCkZvciB0aGF0IHdlIHdpbGwgcGxvdCB0aGUgZnJlcXVlbmN5IG9mIGVhY2ggc2FtcGxlIG9BcyByZWNvbW1lbmRlZCBieSBTb25lc29uIGV0IGFsbC4gYW5kIENyb3dlbGwgZXQgYWwuLCB3ZSB1c2UgYW4gYWdncmVnYXRpb24tYmFzZWQgKHBzZXVkb2J1bGspIHdvcmtmbG4gZWFjaCBjbHVzdGVyICh0aGF0IGlzLCB0aGUgZnJhY3Rpb24gb2YgdGhlIHRvdGFsIGNlbGxzIG9mIHRoYXQgZ2l2ZW4gdHlwZSBwcmVzZW50IG9uIGVhY2ggY2x1c3RlcikuCgpgYGB7ciBUX2VucmljaG1lbnRfY2FsYywgZmlnLmhlaWdodD00MCwgZmlnLndpZHRoPTEwfQoKIyBTdW1hcml6ZSgpIHBlcmZvcm1zIGFuIG9wZXJhdGlvbiBvdmVyIGEgcm93IG9mIGEgZGF0YWZyYW1lLCBmb3IgZXhhbXBsZSBtZWFuKCkgb3IgY291bnQgbigpLgoKIyBTbG90cyBhcmUgZGF0YWZyYW1lcywgc28gaXQgY2FuIGJlIHVzZWQgYnkgZHBseXIuCnByb3BfY2VsbF9ieV9zYW1wbGUgPC0gU0NQX2RhdGFAbWV0YS5kYXRhICU+JSBncm91cF9ieShTYW1wbGVfTmFtZSwgY2VsbC5jbHVzdGVyLmxhYmVscykgJT4lIAogIHN1bW1hcmlzZShuID0gbigpKSAlPiUgIyBGb3IgZWFjaCBjbHVzdGVyLCBncm91cCB0aGUgY2VsbHMgZnJvbSB0aGUgc2FtZSBzYW1wbGUgdG9nZXRoZXIgYW5kIGNvdW50IHRoZW0uCiAgdW5ncm91cCgpICU+JSBncm91cF9ieShTYW1wbGVfTmFtZSkgJT4lCiAgbXV0YXRlKGZyZXEgPSBuIC8gc3VtKG4pKSAlPiUgIyBHcm91cCB0aGVtIG5vdyBieSBzYW1wbGUsIGFkZCB1cCB0aGUgdG90YWwgbnVtYmVyIG9mIGNlbGxzIGZyb20gdGhhdCBzYW1wbGUgKHJlZ2FyZGxlc3Mgb2YgdGhlIGNsdXN0ZXIgdGhleSBiZWxvbmcgdG8pLiBUaGVuLCBkaXZpZGUgZWFjaCBuIHZhbHVlIChudW1iZXIgb2YgY2VsbHMgb2YgYSBzYW1wbGUgaW4gYSBjZXJ0YWluIGNsdXN0ZXIpLCBvYnRhaW5pbmcgd2hpY2ggZnJhY3Rpb24gb2YgdGhlIHRvdGFsIGNlbGxzIG9mIHRoYXQgZ2l2ZW4gdHlwZSBpcyBwcmVzZW50IG9uIGVhY2ggY2x1c3Rlci4KICBsZWZ0X2pvaW4oU0NQX2RhdGFAbWV0YS5kYXRhICU+JSBzZWxlY3QoU2FtcGxlX05hbWUsIFNhbXBsZV9Hcm91cCkgJT4lIHVuaXF1ZSgpKSAjIEFkZCBtZXRhZGF0YSBpbmZvIGF2YWlsYWJsZSBmb3IgdGhlIGRhdGEsIHNlbGVjdCBvbmx5IHRoZSBTYW1wbGVfTmFtZSBhbmQgU2FtcGxlX0dyb3VwIGZpZWxkcyBhbmQgZGVsZXRlIGR1cGxpY2F0ZXMuCmBgYAoKRm9yIG5vdywgd2lsbCBiZSBvbmx5IGZvY3VzIG9uIGNvbXBhcmluZyB0aGUgY29uZmlybWVkIHR1bW9yYWwgKFQpIGFuZCBoZWFsdGh5IChOKSBzYW1wbGVzLgoKYGBge3IgYm94cGxvdCwgZmlnLmhlaWdodD00MCwgZmlnLndpZHRoPTEwfQoKIyBGaWx0ZXIgb25seSB0aGUgZGVzaXJlZCBncm91cHMgIk4iIGFuZCAiVCIKcHJvcF9jZWxsX2J5X3NhbXBsZV9maWx0ZXJlZCA8LSBwcm9wX2NlbGxfYnlfc2FtcGxlICU+JQogIGZpbHRlcihTYW1wbGVfR3JvdXAgJWluJSBjKCJOIiwgIlQiKSkKYGBgCgpXZSBhcHBseSB0aGUgV2lsY294b24gdGVzdCB0byBmaW5kIG91dCBzaWduaWZpY2FudCBkaWZmZXJlbmNlcyBiZXR3ZWVuIHNhbXBsZSBncm91cHMuIFdlIGZvdW5kIG91dCB0aGF0IHRoZSBjbHVzdGVyIDE4IChhbm5vdGF0ZWQgYXMgZW5kb3RoZWxpYWwgY2VsbHMpIGlzIHRoZSBvbmx5IGdyb3VwIHdpdGggYSBzaWduaWZpY2FudCBlbnJpY2htZW50IGluIHR1bW9yYWwgY2VsbHMuCgpgYGB7cn0KCiMgRXh0cmFjdCBkYXRhIGZvciBTYW1wbGVfR3JvdXAgIlQiIGFuZCBvdGhlciBncm91cHMKCmdyb3VwX1QgPC0gcHJvcF9jZWxsX2J5X3NhbXBsZVtwcm9wX2NlbGxfYnlfc2FtcGxlJFNhbXBsZV9Hcm91cCA9PSAiVCIsIF0KZ3JvdXBfTiA8LSBwcm9wX2NlbGxfYnlfc2FtcGxlW3Byb3BfY2VsbF9ieV9zYW1wbGUkU2FtcGxlX0dyb3VwID09ICJOIiwgXQoKIyBQZXJmb3JtIHQtdGVzdCBmb3IgZWFjaCBjbHVzdGVyCmNsdXN0ZXJzIDwtIGxldmVscyhwcm9wX2NlbGxfYnlfc2FtcGxlJGNlbGwuY2x1c3Rlci5sYWJlbHMpCnBfdmFsdWVzIDwtIG51bWVyaWMobGVuZ3RoKGNsdXN0ZXJzKSkKCmZvciAoaSBpbiBzZXFfYWxvbmcoY2x1c3RlcnMpKSB7CiAgCiAgY2x1c3Rlcl9kYXRhX1QgPC0gZ3JvdXBfVFtncm91cF9UJGNlbGwuY2x1c3Rlci5sYWJlbHMgPT0gY2x1c3RlcnNbaV0sICJmcmVxIl0gCiAgCiAgY2x1c3Rlcl9kYXRhX04gPC0gZ3JvdXBfTltncm91cF9OJGNlbGwuY2x1c3Rlci5sYWJlbHMgPT0gY2x1c3RlcnNbaV0sICJmcmVxIl0KCiAgIyBQZXJmb3JtIHRlc3QgCiAgdGVzdF9yZXN1bHQgPC0gd2lsY294LnRlc3QoY2x1c3Rlcl9kYXRhX1QkZnJlcSwgY2x1c3Rlcl9kYXRhX04kZnJlcSkKCiAgIyBTdG9yZSBwLXZhbHVlIAogIHBfdmFsdWVzW2ldIDwtIHRlc3RfcmVzdWx0JHAudmFsdWUgCiAgCiAgfQoKIyBJZGVudGlmeSBjbHVzdGVycyB3aXRoIHNpZ25pZmljYW50IGVucmljaG1lbnQgKGUuZy4sIHAtdmFsdWUgPCAwLjA1KQoKZW5yaWNoZWRfY2x1c3RlcnMgPC0gY2x1c3RlcnNbcF92YWx1ZXMgPCAwLjA1XQoKIyBQcmludCBvciB2aXN1YWxpemUgdGhlIGVucmljaGVkIGNsdXN0ZXJzCgpwcmludChlbnJpY2hlZF9jbHVzdGVycykgCnByaW50KHBfdmFsdWVzKQpgYGAKClVuZm9ydHVuYWxldGx5LCBhZnRlciBhcHBseWluZyBpbnRlZ3JhdGlvbiwgbm8gY2x1c3RlciBpcyBzaWduaWZpY2FudC4gV2UgcGxvdCB0aGUgcmVzdWx0cyBhbG9uZyB0aGUgc3RhdGlzdGljcyBpbiBhIHBhcGVyLXJlYWR5IGZpZ3VyZS4KCmBgYHtyIGJveHBsb3RfcHVibGlzaCwgZmlnLmhlaWdodD0yMCwgZmlnLndpZHRoPTE1fQoKIyBQbG90IG9ubHkgdGhlIGRlc2lyZWQgZ3JvdXBzCmVucmljaGVkX2NsdXN0ZXJzIDwtIGdnYm94cGxvdChwcm9wX2NlbGxfYnlfc2FtcGxlX2ZpbHRlcmVkLCB4ID0gIlNhbXBsZV9Hcm91cCIsIHkgPSAiZnJlcSIsCiAgICAgICAgICBjb2xvciA9ICJTYW1wbGVfR3JvdXAiLCAgcGFsZXR0ZSA9ICJqY28iLAogICAgICAgICAgYWRkID0gImppdHRlciIpICsKZmFjZXRfd3JhcCh+Y2VsbC5jbHVzdGVyLmxhYmVscywgc2NhbGVzID0gImZyZWUiLCBucm93ID0gNikgKwp0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsKeGxhYigiU2FtcGxlIEdyb3VwIikgKyB5bGFiKCJGcmVxdWVuY3kiKSArCnN0YXRfY29tcGFyZV9tZWFucyhhZXMobGFiZWwgPSAuLnAuc2lnbmlmLi4pLCBsYWJlbC54ID0gMS41KQoKZW5yaWNoZWRfY2x1c3RlcnMKYGBgCgojIyMgNi4xLjEuIEZpbmRpbmcgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIGdlbmVzIGluIHR1bW9yYWwtZW5yaWNoZWQgY2x1c3RlcnMuCgpBbnl3YXksIGluIG9yZGVyIHRvIHRlc3QgdGhpcyBuZXcgbWV0aG9kLCB3ZSB3aWxsIG5vdyBwZXJmb3JtIGEgREUgYW5hbHlzaXMgb24gY2x1c3RlciAxOCBieSBjb21wYXJpbmcgY2VsbHMgY29taW5nIGZyb20gVCBzYW1wbGVzICh0dW1vcmFsKSB2cyBoZWFsdGh5IHNhbXBsZXMgKE4pLgoKYGBge3IgREVfYW5hbHlzaXN9CgojIEJ5LWNlbGwgbWV0aG9kICh1c2VzIGludGVncmF0ZWQgYW5kIFNDVHJhbnNmb3JtZWQgZGF0YSkKU0NQX2RhdGEgPC0gUHJlcFNDVEZpbmRNYXJrZXJzKFNDUF9kYXRhKQpjbHVzdGVyMTgubWFya2Vycy5jZWxsIDwtIEZpbmRNYXJrZXJzKFNDUF9kYXRhLCBpZGVudC4xID0gIlQiLCBpZGVudC4yID0gIk4iLCBncm91cC5ieSA9ICJTYW1wbGVfR3JvdXAiLCBzdWJzZXQuaWRlbnQgPSAiMTgtVF9jZWxscyIsIGFzc2F5ID0gIlNDVCIsIHJlY29ycmVjdF91bWkgPSBGQUxTRSkKCiMgVXNpbmcgcHNldWRvYnVsay4KYnVsayA8LSBBZ2dyZWdhdGVFeHByZXNzaW9uKFNDUF9kYXRhLCByZXR1cm4uc2V1cmF0ID0gVCwgc2xvdCA9ICJjb3VudHMiLCBhc3NheXMgPSAiUk5BIiwgZ3JvdXAuYnkgPSBjKCJzZXVyYXRfY2x1c3RlcnMiLAogICAgIlNhbXBsZV9OYW1lIiwgIlNhbXBsZV9Hcm91cCIpKQoKIyBXZSBkb24ndCBrbm93IHdoeSBpdCBhZGRzIGEgImciIGFmdGVyIHBzZXVkb2J1bGtpbmcuIApjbHVzdGVyMTggPC0gc3Vic2V0KGJ1bGssIHNldXJhdF9jbHVzdGVycyA9PSAiZzE4IikKIyBBcyB3ZSBhcmUgdXNpbmcgYnVsa3MgaW5zdGVhZCBvZiBjZWxscywgd2UgbmVlZCB0byBjaGFuZ2UgdGhlIHRlc3QgdG8gYSBtb3JlIGFwcHJvcGlhdGUgb25lLgpjbHVzdGVyMTgubWFya2Vycy5idWxrIDwtIEZpbmRNYXJrZXJzKGNsdXN0ZXIxOCwgaWRlbnQuMSA9ICJUIiwgaWRlbnQuMiA9ICJOIiwgZ3JvdXAuYnkgPSAiU2FtcGxlX0dyb3VwIiwgdGVzdC51c2UgPSAiREVTZXEyIikKYGBgCgpQbG90IGNlbGwtYmFzZWQgREU6CgpgYGB7ciBjZWxsX0RFLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD0xMH0KCkZDID0gbG9nMigxLjUpICMgU2V0IEZDIHRocmVzaG9sZC4KCiMgQWRkIGEgY29sdW1uIHRvIHRoZSBkYXRhIGZyYW1lIHRvIHNwZWNpZnkgaWYgdGhleSBhcmUgVVAtIG9yIERPV04tIHJlZ3VsYXRlZCAobG9nMmZjIHJlc3BlY3RpdmVseSBwb3NpdGl2ZSBvciBuZWdhdGl2ZSkuCmNsdXN0ZXIxOC5tYXJrZXJzLmNlbGwkZGlmZmV4cHJlc3NlZCA8LSAiTk8iCiMgaWYgRkMgPiAxLjUgKGxvZzJGQyA+IH4wLjYpIGFuZCBwdmFsdWUgPCAwLjA1LCBzZXQgYXMgIlVQIi4KY2x1c3RlcjE4Lm1hcmtlcnMuY2VsbCRkaWZmZXhwcmVzc2VkW2NsdXN0ZXIxOC5tYXJrZXJzLmNlbGwkYXZnX2xvZzJGQyA+IEZDICYgY2x1c3RlcjE4Lm1hcmtlcnMuY2VsbCRwX3ZhbCA8IDAuMDVdIDwtICJVUCIKIyBpZiBGQyA8IDAuNjY2IChpbnZlcnMgMS8xLjUgY2FsY3VsYXRlZCBhcyBsb2cyRkMgPCB+LTAuNikgYW5kIHB2YWx1ZSA8IDAuMDUsIHNldCBhcyAiRE9XTiIuCmNsdXN0ZXIxOC5tYXJrZXJzLmNlbGwkZGlmZmV4cHJlc3NlZFtjbHVzdGVyMTgubWFya2Vycy5jZWxsJGF2Z19sb2cyRkMgPCAtRkMgJiBjbHVzdGVyMTgubWFya2Vycy5jZWxsJHBfdmFsIDwgMC4wNV0gPC0gIkRPV04iCgpjbHVzdGVyMTgubWFya2Vycy5jZWxsIDwtIGNsdXN0ZXIxOC5tYXJrZXJzLmNlbGwgJT4lCiAgYXJyYW5nZShwX3ZhbCkgJT4lCiAgbXV0YXRlKGdlbmVfc3ltYm9sID0gcm93bmFtZXMoLikpICU+JQogIGdyb3VwX2J5KGRpZmZleHByZXNzZWQpICU+JQogIG11dGF0ZShkZWxhYmVsID0gaWZfZWxzZShkaWZmZXhwcmVzc2VkICVpbiUgYygiVVAiLCAiRE9XTiIpICYgcm93X251bWJlcigpIDw9IDEwLCBnZW5lX3N5bWJvbCwgTkEpKSAlPiUKICB1bmdyb3VwKCkKCmNlbGwuREUgPC0gZ2dwbG90KGNsdXN0ZXIxOC5tYXJrZXJzLmNlbGwsIGFlcyh4ID0gYXZnX2xvZzJGQywgeSA9IC1sb2cxMChwX3ZhbCksIGNvbCA9IGRpZmZleHByZXNzZWQsIGxhYmVsID0gZGVsYWJlbCkpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBjKC1GQywgRkMpLCBjb2wgPSAiZ3JleSIsIGxpbmV0eXBlID0gJ2Rhc2hlZCcpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAtbG9nMTAoMC4wNSksIGNvbCA9ICJncmV5IiwgbGluZXR5cGUgPSAnZGFzaGVkJykgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiIzAwQUZCQiIsICJncmV5IiwgIiNiYjBjMDAiKSwgIyB0byBzZXQgdGhlIGNvbG91cnMgb2Ygb3VyIHZhcmlhYmxlCiAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIkRvd25yZWd1bGF0ZWQiLCAiTm90IHNpZ25pZmljYW50IiwgIlVwcmVndWxhdGVkIikpICsgIyB0byBzZXQgdGhlIGxhYmVscyBpbiBjYXNlIHdlIHdhbnQgdG8gb3ZlcndyaXRlIHRoZSBjYXRlZ29yaWVzIGZyb20gdGhlIGRhdGFmcmFtZSAoVVAsIERPV04sIE5PKQogIGxhYnMoY29sb3IgPSBOVUxMLCAjbGVnZW5kX3RpdGxlLAogICAgICAgeCA9IGV4cHJlc3Npb24oImxvZyJbMl0qIkZDIiksIHkgPSBleHByZXNzaW9uKCItbG9nIlsxMF0qInAtdmFsdWUiKSkgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgtMTAsIDEwLCAyKSkgKyAjIHRvIGN1c3RvbWlzZSB0aGUgYnJlYWtzIGluIHRoZSB4IGF4aXMKICBnZW9tX3RleHRfcmVwZWwoYm94LnBhZGRpbmcgPSAwLjYsIG1heC5vdmVybGFwcyA9IEluZikgIyBUbyBzaG93IGFsbCBsYWJlbHMKYGBgCgpQbG90IGJ1bGstYmFzZWQgREU6IAoKYGBge3IgYnVsa19ERSwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTB9CgojIEFkZCBhIGNvbHVtbiB0byB0aGUgZGF0YSBmcmFtZSB0byBzcGVjaWZ5IGlmIHRoZXkgYXJlIFVQLSBvciBET1dOLSByZWd1bGF0ZWQgKGxvZzJmYyByZXNwZWN0aXZlbHkgcG9zaXRpdmUgb3IgbmVnYXRpdmUpLgpjbHVzdGVyMTgubWFya2Vycy5idWxrJGRpZmZleHByZXNzZWQgPC0gIk5PIgojIGlmIEZDID4gMS41IChsb2cyRkMgPiB+MC42KSBhbmQgcHZhbHVlIDwgMC4wNSwgc2V0IGFzICJVUCIuCmNsdXN0ZXIxOC5tYXJrZXJzLmJ1bGskZGlmZmV4cHJlc3NlZFtjbHVzdGVyMTgubWFya2Vycy5idWxrJGF2Z19sb2cyRkMgPiBGQyAmIGNsdXN0ZXIxOC5tYXJrZXJzLmJ1bGskcF92YWwgPCAwLjA1XSA8LSAiVVAiCiMgaWYgRkMgPCAwLjY2NiAoaW52ZXJzIDEvMS41IGNhbGN1bGF0ZWQgYXMgbG9nMkZDIDwgfi0wLjYpIGFuZCBwdmFsdWUgPCAwLjA1LCBzZXQgYXMgIkRPV04iLgpjbHVzdGVyMTgubWFya2Vycy5idWxrJGRpZmZleHByZXNzZWRbY2x1c3RlcjE4Lm1hcmtlcnMuYnVsayRhdmdfbG9nMkZDIDwgLUZDICYgY2x1c3RlcjE4Lm1hcmtlcnMuYnVsayRwX3ZhbCA8IDAuMDVdIDwtICJET1dOIgoKY2x1c3RlcjE4Lm1hcmtlcnMuYnVsayA8LSBjbHVzdGVyMTgubWFya2Vycy5idWxrICU+JQogIGFycmFuZ2UocF92YWxfYWRqKSAlPiUKICBtdXRhdGUoZ2VuZV9zeW1ib2wgPSByb3duYW1lcyguKSkgJT4lCiAgZ3JvdXBfYnkoZGlmZmV4cHJlc3NlZCkgJT4lCiAgbXV0YXRlKGRlbGFiZWwgPSBpZl9lbHNlKGRpZmZleHByZXNzZWQgJWluJSBjKCJVUCIsICJET1dOIikgJiByb3dfbnVtYmVyKCkgPD0gMTAsIGdlbmVfc3ltYm9sLCBOQSkpICU+JQogIHVuZ3JvdXAoKQoKYnVsay5ERSA8LSBnZ3Bsb3QoY2x1c3RlcjE4Lm1hcmtlcnMuYnVsaywgYWVzKHggPSBhdmdfbG9nMkZDLCB5ID0gLWxvZzEwKHBfdmFsKSwgY29sID0gZGlmZmV4cHJlc3NlZCwgbGFiZWwgPSBkZWxhYmVsKSkgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGMoLUZDLCBGQyksIGNvbCA9ICJncmV5IiwgbGluZXR5cGUgPSAnZGFzaGVkJykgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IC1sb2cxMCgwLjA1KSwgY29sID0gImdyZXkiLCBsaW5ldHlwZSA9ICdkYXNoZWQnKSArCiAgZ2VvbV9wb2ludChzaXplID0gMikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCIjMDBBRkJCIiwgImdyZXkiLCAiI2JiMGMwMCIpLCAjIHRvIHNldCB0aGUgY29sb3VycyBvZiBvdXIgdmFyaWFibGUKICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiRG93bnJlZ3VsYXRlZCIsICJOb3Qgc2lnbmlmaWNhbnQiLCAiVXByZWd1bGF0ZWQiKSkgKyAjIHRvIHNldCB0aGUgbGFiZWxzIGluIGNhc2Ugd2Ugd2FudCB0byBvdmVyd3JpdGUgdGhlIGNhdGVnb3JpZXMgZnJvbSB0aGUgZGF0YWZyYW1lIChVUCwgRE9XTiwgTk8pCiAgbGFicyhjb2xvciA9IE5VTEwsICNsZWdlbmRfdGl0bGUsCiAgICAgICB4ID0gZXhwcmVzc2lvbigibG9nIlsyXSoiRkMiKSwgeSA9IGV4cHJlc3Npb24oIi1sb2ciWzEwXSoicC12YWx1ZSIpKSArCiAgdGhlbWVfY2xhc3NpYygpICsKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKC0xMCwgMTAsIDIpKSArICMgdG8gY3VzdG9taXNlIHRoZSBicmVha3MgaW4gdGhlIHggYXhpcwogIGdlb21fdGV4dF9yZXBlbChib3gucGFkZGluZyA9IDAuNiwgbWF4Lm92ZXJsYXBzID0gSW5mKSAjIFRvIHNob3cgYWxsIGxhYmVscwpgYGAKCkNvbXBhcmU6CgpgYGB7ciBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD0yMH0KCmNlbGwuREUgKyBidWxrLkRFCmBgYAoKYGBge3Igc2Vzc2lvbl9pbmZvfQoKc2Vzc2lvbkluZm8oKQpSTkdraW5kKCkKYGBgCg==